﻿///////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2023, ООО 1С-Софт
// Все права защищены. Эта программа и сопроводительные материалы предоставляются 
// в соответствии с условиями лицензии Attribution 4.0 International (CC BY 4.0)
// Текст лицензии доступен по ссылке:
// https://creativecommons.org/licenses/by/4.0/legalcode
///////////////////////////////////////////////////////////////////////////////////////////////////////

#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда

#Область СлужебныйПрограммныйИнтерфейс

// Сообщает все требуемые сведения о процедуре загрузки данных из файла для внешней обработки.
//
// Параметры: 
//    ИмяКоманды - Строка - имя команды (Идентификатор).
//    СсылкаНаОбработку - ЛюбаяСсылка - ссылка на обработку.
//    ПараметрыЗагрузки - Структура:
//     * Представление                           - Строка - представление в списке вариантов загрузки.
//     * ИмяМакетаСШаблоном                      - Строка - название макета со структурой данных(необязательный
//                                                          параметр, значение по умолчанию - "ЗагрузкаДанныхИзФайла").
//     * ОбязательныеКолонкиМакета               - Массив - содержит список обязательных полей для заполнения.
//     * ЗаголовокКолонкиСопоставления            - Строка - представление колонки сопоставления в шапке таблицы
//                                                           сопоставления данных(необязательный параметр, значение по
//                                                           умолчанию формируются - "Справочник: <синоним
//                                                           справочника>").
//     * ИмяОбъекта                               - Строка - имя Объекта.
//
Процедура ПараметрыЗагрузкиИзФайлаВнешняяОбработка(ИмяКоманды, СсылкаНаОбработку, ПараметрыЗагрузки) Экспорт
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ДополнительныеОтчетыИОбработки") Тогда
		МодульДополнительныеОтчетыИОбработки = ОбщегоНазначения.ОбщийМодуль("ДополнительныеОтчетыИОбработки");
		ВнешнийОбъект = МодульДополнительныеОтчетыИОбработки.ОбъектВнешнейОбработки(СсылкаНаОбработку);
		ВнешнийОбъект.ОпределитьПараметрыЗагрузкиДанныхИзФайла(ИмяКоманды, ПараметрыЗагрузки);
		ПараметрыЗагрузки.Вставить("Макет", ВнешнийОбъект.ПолучитьМакет(ПараметрыЗагрузки.ИмяМакетаСШаблоном));
	КонецЕсли;
	
КонецПроцедуры

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

// Сообщает все требуемые сведения о процедуре загрузки данных из файла в Табличную часть.
Функция ПараметрыЗагрузкиИзФайлаВТЧ(ИмяТабличнойЧасти, ДополнительныеПараметры)
	
	ПараметрыПоУмолчанию= Новый Структура;
	ПараметрыПоУмолчанию.Вставить("ОбязательныеКолонки", Новый Массив);
	ПараметрыПоУмолчанию.Вставить("ИмяМакетаСШаблоном", "ЗагрузкаИзФайла");
	ПараметрыПоУмолчанию.Вставить("ИмяТабличнойЧасти", ИмяТабличнойЧасти);
	ПараметрыПоУмолчанию.Вставить("ТипДанныхКолонки", Новый Соответствие);
	ПараметрыПоУмолчанию.Вставить("ДополнительныеПараметры", ДополнительныеПараметры);
	
	Возврат ПараметрыПоУмолчанию;
	
КонецФункции

Процедура СоздатьСписокСправочниковДляЗагрузки(СписокСправочниковДляЗагрузки) Экспорт
	
	ТипСтрока = Новый ОписаниеТипов("Строка");
	ТипБулево = Новый ОписаниеТипов("Булево");

	ИнформацияОСправочниках = Новый ТаблицаЗначений;
	ИнформацияОСправочниках.Колонки.Добавить("ПолноеИмя", ТипСтрока);
	ИнформацияОСправочниках.Колонки.Добавить("Представление", ТипСтрока);
	ИнформацияОСправочниках.Колонки.Добавить("ПрикладнаяЗагрузка", ТипБулево);
	
	ФункциональныеОпции = СтандартныеПодсистемыПовтИсп.ДоступностьОбъектовПоОпциям();
	
	Для каждого ОбъектМетаданныхДляВывода Из Метаданные.Справочники Цикл
		
		ПолноеИмя = ОбъектМетаданныхДляВывода.ПолноеИмя();
		Если ФункциональныеОпции.Получить(ПолноеИмя) = Ложь Тогда
			Продолжить;
		КонецЕсли;

		Если ЗагрузкаДанныхИзФайлаДопустима(ОбъектМетаданныхДляВывода) Тогда
			Строка = ИнформацияОСправочниках.Добавить();
			Строка.Представление = ОбъектМетаданныхДляВывода.Представление();
			Строка.ПолноеИмя     = ПолноеИмя;
		КонецЕсли;
		
	КонецЦикла;
	
	ИнтеграцияПодсистемБСП.ПриОпределенииСправочниковДляЗагрузкиДанных(ИнформацияОСправочниках);
	ЗагрузкаДанныхИзФайлаПереопределяемый.ПриОпределенииСправочниковДляЗагрузкиДанных(ИнформацияОСправочниках);
	
	ИнформацияОСправочниках.Колонки.Добавить("ИнформацияОТипеЗагрузки");
	
	Для каждого ИнформацияОСправочнике Из ИнформацияОСправочниках Цикл
		ИнформацияОТипеЗагрузки = Новый Структура;
		Если ИнформацияОСправочнике.ПрикладнаяЗагрузка Тогда
			ИнформацияОТипеЗагрузки.Вставить("Тип", "ПрикладнаяЗагрузка");
		Иначе
			ИнформацияОТипеЗагрузки.Вставить("Тип", "УниверсальнаяЗагрузка");
		КонецЕсли;
		ИнформацияОТипеЗагрузки.Вставить("ПолноеИмяОбъектаМетаданных", ИнформацияОСправочнике.ПолноеИмя);
		ИнформацияОСправочнике.ИнформацияОТипеЗагрузки = ИнформацияОТипеЗагрузки;
	КонецЦикла;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.ДополнительныеОтчетыИОбработки") Тогда
		МодульДополнительныеОтчетыИОбработки = ОбщегоНазначения.ОбщийМодуль("ДополнительныеОтчетыИОбработки");
		Запрос = МодульДополнительныеОтчетыИОбработки.НовыйЗапросПоДоступнымКомандам(Перечисления["ВидыДополнительныхОтчетовИОбработок"].ДополнительнаяОбработка,
			Неопределено, Ложь, Перечисления["СпособыВызоваДополнительныхОбработок"].ЗагрузкаДанныхИзФайла);
		ТаблицаКоманд = Запрос.Выполнить().Выгрузить(); // см. ДополнительныеОтчетыИОбработки.НовыйЗапросПоДоступнымКомандам
		
		Для Каждого СтрокаТаблицы Из ТаблицаКоманд Цикл
			ИнформацияОТипеЗагрузки = Новый Структура("Тип", "ВнешняяЗагрузка");
			ИнформацияОТипеЗагрузки.Вставить("ПолноеИмяОбъектаМетаданных", СтрокаТаблицы.Модификатор);
			ИнформацияОТипеЗагрузки.Вставить("Ссылка", СтрокаТаблицы.Ссылка);
			ИнформацияОТипеЗагрузки.Вставить("Идентификатор", СтрокаТаблицы.Идентификатор);
			ИнформацияОТипеЗагрузки.Вставить("Представление", СтрокаТаблицы.Представление);
			
			Строка = ИнформацияОСправочниках.Добавить();
			Строка.ПолноеИмя = ОбъектМетаданныхДляВывода.ПолноеИмя();
			Строка.ИнформацияОТипеЗагрузки = ИнформацияОТипеЗагрузки;
			Строка.Представление = СтрокаТаблицы.Представление;
		КонецЦикла;
	КонецЕсли;
	
	СписокСправочниковДляЗагрузки.Очистить();
	Для каждого ИнформацияОСправочнике Из ИнформацияОСправочниках Цикл 
		
		Если ИнформацияОСправочнике.ПрикладнаяЗагрузка Тогда
			Представление = ПредставлениеСправочника(ИнформацияОСправочнике.ПолноеИмя);
			Если ПустаяСтрока(Представление) Тогда
				Представление = ИнформацияОСправочнике.Представление;
			КонецЕсли;
		Иначе
			Представление = ИнформацияОСправочнике.Представление;
		КонецЕсли;
		
		СписокСправочниковДляЗагрузки.Добавить(ИнформацияОСправочнике.ИнформацияОТипеЗагрузки, Представление);
		
	КонецЦикла;
		
	СписокСправочниковДляЗагрузки.СортироватьПоПредставлению();
	
КонецПроцедуры 

Функция ПредставлениеСправочника(ИмяОбъектаСопоставления)
	
	ПараметрыЗагрузкиПоУмолчанию = ЗагрузкаДанныхИзФайла.ПараметрыЗагрузкиИзФайла(ИмяОбъектаСопоставления);
	МенеджерОбъекта(ИмяОбъектаСопоставления).ОпределитьПараметрыЗагрузкиДанныхИзФайла(ПараметрыЗагрузкиПоУмолчанию);
	
	Возврат ПараметрыЗагрузкиПоУмолчанию.Заголовок;
	
КонецФункции

Функция ЗагрузкаДанныхИзФайлаДопустима(Справочник)
	
	Если СтрНачинаетсяС(ВРег(Справочник.Имя), ВРег("УДАЛИТЬ")) Тогда
		Возврат Ложь;
	КонецЕсли;
	
	Для каждого ТабличнаяЧасть Из Справочник.ТабличныеЧасти Цикл
		Если ТабличнаяЧасть.Имя <> "КонтактнаяИнформация"
			И ТабличнаяЧасть.Имя <> "ДополнительныеРеквизиты"
			И ТабличнаяЧасть.Имя <> "Представления"
			И ТабличнаяЧасть.Имя <> "СертификатыШифрования" Тогда
				Возврат Ложь;
		КонецЕсли;
	КонецЦикла;
	
	Для каждого Реквизит Из Справочник.Реквизиты Цикл 
		Для каждого ТипРеквизита Из Реквизит.Тип.Типы() Цикл
			Если ТипРеквизита = Тип("ХранилищеЗначения") Тогда
				Возврат Ложь;
			КонецЕсли;
		КонецЦикла;
	КонецЦикла;
	
	Возврат Истина;
	
КонецФункции

#Область ПоискСсылок


// Описание
// 
// Параметры:
//  ШаблонСДанными - ТабличныйДокумент
//  ИнформацияПоКолонкам - ТаблицаЗначений:
//   * ИмяКолонки - Строка
//   * Идентификатор - Строка
//   * ПредставлениеКолонки - Строка
//   * ТипКолонки - Произвольный
//   * ОбязательнаДляЗаполнения - Булево
//   * Позиция - Число
//   * Группа - Строка
//   * Видимость - Булево
//   * Примечание - Строка
//   * Ширина - Число
//  ОписаниеТипов - ОписаниеТипов
// 
Процедура УстановитьРежимВставкиИзБуфераОбмена(ШаблонСДанными, ИнформацияПоКолонкам, ОписаниеТипов) Экспорт
	СоответствиеКолонок = Новый Соответствие;
	ЗаголовокКолонки    = "";
	Разделитель         = "";
	ТипыОбъектовПоддерживающиеВводПоСтроке = ТипыОбъектовПоддерживающиеВводПоСтроке();
	
	Для каждого Тип Из ОписаниеТипов.Типы() Цикл
		ОбъектМетаданных = Метаданные.НайтиПоТипу(Тип); // ОбъектМетаданныхСправочник, ОбъектМетаданныхДокумент
		
		Если ОбъектМетаданных <> Неопределено Тогда
			СтруктураОбъекта = РазложитьПолноеИмяОбъекта(ОбъектМетаданных.ПолноеИмя());
			
			Если ТипыОбъектовПоддерживающиеВводПоСтроке[СтруктураОбъекта.ТипОбъекта] = Истина Тогда
				
				Для каждого Колонка Из ОбъектМетаданных.ВводПоСтроке Цикл
					
					Если СоответствиеКолонок.Получить(Колонка.Имя) = Неопределено Тогда
						ЗаголовокКолонки = ЗаголовокКолонки + Разделитель + Колонка.Имя;
						Разделитель = ", ";
						СоответствиеКолонок.Вставить(Колонка.Имя, Колонка.Имя);
					КонецЕсли;
					
				КонецЦикла;
				
			КонецЕсли;
			
			Если СтруктураОбъекта.ТипОбъекта = "Документ" Тогда
				ЗаголовокКолонки = ЗаголовокКолонки + Разделитель + "Представление";
			КонецЕсли;
		КонецЕсли;
		
		ЗаголовокКолонки = НСтр("ru = 'Введенные данные'");
		
	КонецЦикла;
	
	ДобавитьИнформациюПоКолонке(ИнформацияПоКолонкам, "Ссылки", ЗаголовокКолонки, Новый ОписаниеТипов("Строка"), Ложь, 1);
	
	Шапка = ШапкаБланкаДляЗаполненияПоИнформацииПоКолонкам(ИнформацияПоКолонкам);
	ШаблонСДанными.Очистить();
	ШаблонСДанными.Вывести(Шапка);
	
КонецПроцедуры

Функция ТипыОбъектовПоддерживающиеВводПоСтроке()
	
	СписокОбъектов = Новый Соответствие;
	СписокОбъектов.Вставить("БизнесПроцесс",          Истина);
	СписокОбъектов.Вставить("Документ",               Истина);
	СписокОбъектов.Вставить("Задача",                 Истина);
	СписокОбъектов.Вставить("ПланВидовРасчета",       Истина);
	СписокОбъектов.Вставить("ПланВидовХарактеристик", Истина);
	СписокОбъектов.Вставить("ПланОбмена",             Истина);
	СписокОбъектов.Вставить("ПланСчетов",             Истина);
	СписокОбъектов.Вставить("Справочник",             Истина);
	
	Возврат СписокОбъектов;
	
КонецФункции

Процедура СопоставитьЗначениеКолонкиАвто(ТаблицаСопоставления, ИмяКолонки) Экспорт
	
	Типы = ТаблицаСопоставления.Колонки.ОбъектСопоставления.ТипЗначения.Типы();
	ТипыОбъектовПоддерживающиеВводПоСтроке = ТипыОбъектовПоддерживающиеВводПоСтроке();
	
	ЗначенияДляСопоставления = Новый ТаблицаЗначений();
	
	ТекстЗапроса = "";
	
	Для каждого Тип Из Типы Цикл
		ОбъектМетаданных = Метаданные.НайтиПоТипу(Тип); // ОбъектМетаданныхСправочник, ОбъектМетаданныхДокумент
		Если ОбъектМетаданных <> Неопределено И ПравоДоступа("Чтение", ОбъектМетаданных) Тогда
			СтруктураОбъекта = РазложитьПолноеИмяОбъекта(ОбъектМетаданных.ПолноеИмя());
			
			МассивКолонок = Новый Массив;
			Если ТипыОбъектовПоддерживающиеВводПоСтроке[СтруктураОбъекта.ТипОбъекта] = Истина Тогда
				Для каждого Поле Из ОбъектМетаданных.ВводПоСтроке Цикл
					МассивКолонок.Добавить(Поле.Имя);
				КонецЦикла;
				Если СтруктураОбъекта.ТипОбъекта = "Документ" Тогда
					МассивКолонок.Добавить("Ссылка");
				КонецЕсли;
			КонецЕсли;
			
			ТекстЗапроса = СтрокаЗапроса(ТекстЗапроса, СтруктураОбъекта.ТипОбъекта,
				СтруктураОбъекта.НазваниеОбъекта, МассивКолонок);
		КонецЕсли;
	КонецЦикла;
	
	Если ПустаяСтрока(ТекстЗапроса) Тогда
		Возврат;
	КонецЕсли;
	
	ТекстЗапроса = "ВЫБРАТЬ
		|ЗначенияДляСопоставления.ЗначениеПоиска КАК ЗначениеПоиска, 
		|ЗначенияДляСопоставления.Ключ КАК Ключ
		|ПОМЕСТИТЬ ЗначенияДляСопоставления
		|ИЗ
		|	&ЗначенияДляСопоставления КАК ЗначенияДляСопоставления" 
		+ ОбщегоНазначения.РазделительПакетаЗапросов()
		+ ТекстЗапроса + "
		|ИТОГИ ПО Ключ";
	
	Типы.Добавить(Тип("Строка"));
	ПараметрыСтроки = Новый КвалификаторыСтроки(500);
	ДопустимыеТипы = Новый ОписаниеТипов(Типы, , ПараметрыСтроки);
	ЗначенияДляСопоставления.Колонки.Добавить("ЗначениеПоиска", ДопустимыеТипы);
	ЗначенияДляСопоставления.Колонки.Добавить("Ключ", ОбщегоНазначения.ОписаниеТипаЧисло(10));
	
	Для каждого Строка Из ТаблицаСопоставления Цикл 
		Если НЕ ЗначениеЗаполнено(Строка[ИмяКолонки]) Тогда 
			Продолжить;
		КонецЕсли;
		
		Значение = ДокументПоПредставлению(Строка[ИмяКолонки], Типы);
		НоваяСтрока = ЗначенияДляСопоставления.Добавить();
		НоваяСтрока.ЗначениеПоиска =?(Значение = Неопределено, СокрЛП(Строка[ИмяКолонки]), Значение);
		НоваяСтрока.Ключ = ТаблицаСопоставления.Индекс(Строка);

	КонецЦикла;
	
	Запрос = Новый Запрос(ТекстЗапроса);
	Запрос.УстановитьПараметр("ЗначенияДляСопоставления", ЗначенияДляСопоставления);

	ТаблицаРезультатов = Запрос.Выполнить().Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);

	Пока ТаблицаРезультатов.Следующий() Цикл

		РезультатПоиска = ТаблицаРезультатов.Выбрать();
		СтрокаДанных = ТаблицаСопоставления.Получить(ТаблицаРезультатов.Ключ);
		Если СтрокаДанных = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		
		НайденныеВарианты = Новый Массив;
		Пока РезультатПоиска.Следующий() Цикл
			Если РезультатПоиска.СсылкаНаОбъект <> Неопределено Тогда
				НайденныеВарианты.Добавить(РезультатПоиска.СсылкаНаОбъект);
			КонецЕсли;
		КонецЦикла;

		Если НайденныеВарианты.Количество() = 1 Тогда
			СтрокаДанных.ОбъектСопоставления = НайденныеВарианты[0];
			СтрокаДанных.РезультатСопоставленияСтроки =  ЗагрузкаДанныхИзФайлаКлиентСервер.СтатусСопоставлен();
		ИначеЕсли НайденныеВарианты.Количество() > 1 Тогда
			СтрокаДанных.СписокНеоднозначностей.ЗагрузитьЗначения(НайденныеВарианты);
			СтрокаДанных.РезультатСопоставленияСтроки = ЗагрузкаДанныхИзФайлаКлиентСервер.СтатусНеоднозначность();
		Иначе
			СтрокаДанных.РезультатСопоставленияСтроки = ЗагрузкаДанныхИзФайлаКлиентСервер.СтатусНеСопоставлен();
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры

// Распознает документ по представлению для режима поиска ссылок.
//
Функция ДокументПоПредставлению(Представление, Типы)
	
	Для каждого Тип Из Типы Цикл
		ОбъектМетаданных = Метаданные.НайтиПоТипу(Тип);
		Если ОбъектМетаданных = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		СтруктураИмениОбъекта = РазложитьПолноеИмяОбъекта(ОбъектМетаданных.ПолноеИмя());
		Если ВРег(СтруктураИмениОбъекта.ТипОбъекта) <> ВРег("Документ") Тогда
			Продолжить;
		КонецЕсли;
		
		ПредставлениеЭлемента = ОбщегоНазначения.ПредставлениеОбъекта(ОбъектМетаданных);
		
		Если СтрНайти(Представление, ПредставлениеЭлемента) > 0 Тогда
			ПредставлениеНомерИДата = СокрЛП(Сред(Представление, СтрДлина(ПредставлениеЭлемента) + 1));
			ПозицияОкончанияНомера = СтрНайти(ПредставлениеНомерИДата, " ");
			Номер = Лев(ПредставлениеНомерИДата, ПозицияОкончанияНомера - 1);
			ПозицияОт = СтрНайти(НРег(ПредставлениеНомерИДата), НСтр("ru = 'от'"));
			ПредставлениеДата = СокрЛ(Сред(ПредставлениеНомерИДата, ПозицияОт + 2));
			ПозицияОкончаниеДаты = СтрНайти(ПредставлениеДата, " ");
			ДатаОкругленнаяДоДня = Лев(ПредставлениеДата, ПозицияОкончаниеДаты - 1) + " 00:00:00";
			НомерДокумент = Номер;
			ДатаДокумента = СтроковыеФункцииКлиентСервер.СтрокаВДату(ДатаОкругленнаяДоДня);
		КонецЕсли;
		
		УстановитьПривилегированныйРежим(Истина);
		Документ = Документы[ОбъектМетаданных.Имя].НайтиПоНомеру(НомерДокумент, ДатаДокумента); // ОбъектМетаданныхДокумент
		УстановитьПривилегированныйРежим(Ложь);
		
		Если Документ = Неопределено ИЛИ Документ = Документы[ОбъектМетаданных.Имя].ПустаяСсылка() Тогда
			Возврат Неопределено;
		КонецЕсли;
		
		Возврат Документ;
	
	КонецЦикла;
	
	Возврат Неопределено;
	
КонецФункции

Функция СтрокаЗапроса(ТекстЗапроса, ТипОбъекта, ИмяОбъекта, МассивКолонок)
	
	Если МассивКолонок.Количество() = 0 Тогда
		Возврат ТекстЗапроса;
	КонецЕсли;

	ТекстыПО = Новый Массив;
	Для Каждого Поле Из МассивКолонок Цикл 
		ТекстыПО.Добавить("ТаблицаДанных." + Поле + " = ЗначенияДляСопоставления.ЗначениеПоиска");
	КонецЦикла;
	
	ТекстШаблон = "ВЫБРАТЬ РАЗРЕШЕННЫЕ
	|	ЕСТЬNULL(ТаблицаДанных.Ссылка, Неопределено) КАК СсылкаНаОбъект,
	|	ЗначенияДляСопоставления.Ключ КАК Ключ
	|ИЗ
	|	ЗначенияДляСопоставления КАК ЗначенияДляСопоставления 
	|	ЛЕВОЕ СОЕДИНЕНИЕ &ИмяТаблицы КАК ТаблицаДанных
	|	ПО &Условия";
	ТекстШаблон = СтрЗаменить(ТекстШаблон, "&Условия", СтрСоединить(ТекстыПО, " ИЛИ ")); // @query-part-2
	ТекстШаблон = СтрЗаменить(ТекстШаблон, "&ИмяТаблицы", ТипОбъекта + "." + ИмяОбъекта);
	Если Не ПустаяСтрока(ТекстЗапроса) Тогда
		ТекстШаблон = СтрЗаменить(ТекстШаблон, "ВЫБРАТЬ РАЗРЕШЕННЫЕ", "ВЫБРАТЬ"); // @query-part-1, @query-part-2
		ТекстЗапроса = ТекстЗапроса + Символы.ПС + "ОБЪЕДИНИТЬ ВСЕ" + Символы.ПС; // @query-part-1
	КонецЕсли;
	ТекстЗапроса = ТекстЗапроса + ТекстШаблон;
	
	Возврат ТекстЗапроса;
	
КонецФункции

// Добавление информации по колонке для режима поиска ссылок.
//
Процедура ДобавитьИнформациюПоКолонке(ИнформацияПоКолонкам, Имя, Представление, Тип, ОбязательнаДляЗаполнения, Позиция, Группа = "")
	СтрокаИнфоПроКолонки = ИнформацияПоКолонкам.Добавить();
	СтрокаИнфоПроКолонки.ИмяКолонки = Имя;
	СтрокаИнфоПроКолонки.ПредставлениеКолонки = Представление;
	СтрокаИнфоПроКолонки.ТипКолонки = Тип;
	СтрокаИнфоПроКолонки.ОбязательнаДляЗаполнения = ОбязательнаДляЗаполнения;
	СтрокаИнфоПроКолонки.Позиция = Позиция;
	СтрокаИнфоПроКолонки.Группа = ?(ЗначениеЗаполнено(Группа), Группа, Имя);
	СтрокаИнфоПроКолонки.Видимость = Истина;
КонецПроцедуры

#КонецОбласти

// Заполняет таблицу значений сопоставленные данные по данным из макета.
//
// Параметры:
//  ПараметрыВыгрузки - Структура:
//   * ТаблицаСопоставления - ТаблицаЗначений:
//       ** Идентификатор - Строка
//    * ИнформацияПоКолонкам - ТаблицаЗначений
//  АдресХранилища- Строка 
// 
Процедура ЗаполнитьТаблицуСопоставленияДаннымиИзШаблонаФон(ПараметрыВыгрузки, АдресХранилища) Экспорт
	
	ШаблонСДанными = ПараметрыВыгрузки.ШаблонСДанными;
	ТаблицаСопоставления = ПараметрыВыгрузки.ТаблицаСопоставления;
	ИнформацияПоКолонкам = ПараметрыВыгрузки.ИнформацияПоКолонкам;
	
	ТаблицаСопоставления.Очистить();
	ЗаполнитьТаблицуСопоставленияЗагружаемымиДанными(ШаблонСДанными, ИнформацияПоКолонкам, ТаблицаСопоставления, Истина);
	
	ПоместитьВоВременноеХранилище(ТаблицаСопоставления, АдресХранилища);
	
КонецПроцедуры

Процедура ЗаполнитьТаблицуСопоставленияДаннымиИзШаблона(ШаблонСДанными, ТаблицаСопоставления, ИнформацияПоКолонкам) Экспорт
	
	ОпределитьПозицииКолонокВМакете(ШаблонСДанными, ИнформацияПоКолонкам);
	ТаблицаСопоставления.Очистить();
	ЗаполнитьТаблицуСопоставленияЗагружаемымиДанными(ШаблонСДанными, ИнформацияПоКолонкам, ТаблицаСопоставления);
	
КонецПроцедуры

Процедура ЗаполнитьТаблицуСопоставленияЗагружаемымиДанными(ШаблонСДанными, ТаблицаИнформацияПоКолонкам, ТаблицаСопоставления, ФоновоеЗадание = Ложь)
	
	ПерваяСтрокаТаблицы = ?(ЗагрузкаДанныхИзФайлаКлиентСервер.КолонкиИмеютГруппировку(ТаблицаИнформацияПоКолонкам), 3, 2);
	
	КоличествоПустыхСтрок = 0;
	КоличествоПустыхСтрокПодрядДляПрерыванияЗагрузки = 30;
	
	КорректировкаИдентификатора = ПерваяСтрокаТаблицы - 2;
	Для НомерСтроки = ПерваяСтрокаТаблицы По ШаблонСДанными.ВысотаТаблицы Цикл 
		СтрокаТаблицыПустая = Истина;
		НоваяСтрока = ТаблицаСопоставления.Добавить();
		НоваяСтрока.Идентификатор = НомерСтроки - 1 - КорректировкаИдентификатора;
		НоваяСтрока.РезультатСопоставленияСтроки = ЗагрузкаДанныхИзФайлаКлиентСервер.СтатусНеСопоставлен();
		
		Для НомерКолонки = 1 По ШаблонСДанными.ШиринаТаблицы Цикл
			
			Ячейка = ШаблонСДанными.ПолучитьОбласть(НомерСтроки, НомерКолонки, НомерСтроки, НомерКолонки).ТекущаяОбласть;
			Колонка = НайтиИнформациюОКолонке(ТаблицаИнформацияПоКолонкам, "Позиция", НомерКолонки);
			
			Если Колонка <> Неопределено Тогда
				
				ДанныеЯчейки =  Неопределено;
				
				ИмяКолонки = Колонка.ИмяКолонки;
				ТипДанных = ТипЗнч(НоваяСтрока[ИмяКолонки]);
				
				Если ТипДанных <> Тип("Строка") И ТипДанных <> Тип("Булево") И ТипДанных <> Тип("Число") И ТипДанных <> Тип("Дата")  И ТипДанных <> Тип("УникальныйИдентификатор") Тогда 
					//@skip-check query-in-loop - построчная загрузка разнородных данных.
					ДанныеЯчейки = ЗначениеЯчейки(Колонка, Ячейка.Текст);
				Иначе
					Если ТипДанных = Тип("Булево") Тогда
						ЗначениеЯчейки = ВРег(СокрЛП(Ячейка.Текст));
						Если ЗначениеЯчейки = "1" 
						   Или СтрСравнить(ЗначениеЯчейки, ЗагрузкаДанныхИзФайлаКлиентСервер.ПредставлениеТекстаДаДляБулево()) = 0
						   Или СтрСравнить(ЗначениеЯчейки, "ИСТИНА") = 0 Тогда
							ДанныеЯчейки = Истина;
						Иначе
							ДанныеЯчейки = Ложь;
						КонецЕсли;
					Иначе
						ДанныеЯчейки = Ячейка.Текст;
					КонецЕсли;
				КонецЕсли;
				Если СтрокаТаблицыПустая Тогда
					СтрокаТаблицыПустая = НЕ ЗначениеЗаполнено(ДанныеЯчейки);
				КонецЕсли;
				НоваяСтрока[ИмяКолонки] = ДанныеЯчейки;
			КонецЕсли;
		КонецЦикла;
		Если СтрокаТаблицыПустая Тогда
			ТаблицаСопоставления.Удалить(НоваяСтрока);
			КорректировкаИдентификатора = КорректировкаИдентификатора + 1;
			КоличествоПустыхСтрок       = КоличествоПустыхСтрок + 1;
		Иначе
			КоличествоПустыхСтрок       = 0;
		КонецЕсли;
		
		Если КоличествоПустыхСтрок > КоличествоПустыхСтрокПодрядДляПрерыванияЗагрузки Тогда
			Прервать;
		КонецЕсли;
		
		Если ФоновоеЗадание Тогда
			Процент = Окр(НомерСтроки *100 / ШаблонСДанными.ВысотаТаблицы);
			МодульДлительныеОперации = ОбщегоНазначения.ОбщийМодуль("ДлительныеОперации");
			МодульДлительныеОперации.СообщитьПрогресс(Процент);
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры

Функция ЗначениеЯчейки(Колонка, ЗначениеЯчейки)
	
	ДанныеЯчейки = "";
	Для каждого ТипДанных Из Колонка.ТипКолонки.Типы() Цикл
		ОбъектМетаданных = Метаданные.НайтиПоТипу(ТипДанных);
		
		Если ОбъектМетаданных = Неопределено Тогда
			Продолжить;
		КонецЕсли;
		
		ОписаниеОбъекта = РазложитьПолноеИмяОбъекта(ОбъектМетаданных.ПолноеИмя());
		Если ОписаниеОбъекта.ТипОбъекта = "Справочник" Тогда
			Если НЕ ОбъектМетаданных.Автонумерация И ОбъектМетаданных.ДлинаКода > 0 Тогда 
				ДанныеЯчейки = Справочники[ОписаниеОбъекта.НазваниеОбъекта].НайтиПоКоду(ЗначениеЯчейки, Истина);
			КонецЕсли;
			Если Не ЗначениеЗаполнено(ДанныеЯчейки) И ЗначениеЗаполнено(ЗначениеЯчейки) Тогда
				//@skip-check query-in-loop - штучные запросы разнородных данных.
				ДанныеЯчейки = НайтиПоНаименованию(ЗначениеЯчейки, ОбъектМетаданных, Колонка);
			КонецЕсли;
			Если Не ЗначениеЗаполнено(ДанныеЯчейки) Тогда 
				ДанныеЯчейки = Справочники[ОписаниеОбъекта.НазваниеОбъекта].НайтиПоКоду(ЗначениеЯчейки, Истина);
			КонецЕсли;
		ИначеЕсли ОписаниеОбъекта.ТипОбъекта = "Перечисление" Тогда 
			Для каждого ЗначениеПеречисления Из Перечисления[ОписаниеОбъекта.НазваниеОбъекта] Цикл 
				Если Строка(ЗначениеПеречисления) = СокрЛП(ЗначениеЯчейки) Тогда 
					ДанныеЯчейки = ЗначениеПеречисления; 
				КонецЕсли;
			КонецЦикла;
		ИначеЕсли ОписаниеОбъекта.ТипОбъекта = "ПланСчетов" Тогда
			ДанныеЯчейки = ПланыСчетов[ОписаниеОбъекта.НазваниеОбъекта].НайтиПоКоду(ЗначениеЯчейки);
			Если ДанныеЯчейки.Пустая() Тогда 
				ДанныеЯчейки = ПланыСчетов[ОписаниеОбъекта.НазваниеОбъекта].НайтиПоНаименованию(ЗначениеЯчейки, Истина);
			КонецЕсли;
		ИначеЕсли ОписаниеОбъекта.ТипОбъекта = "ПланВидовХарактеристик" Тогда
			Если Не ОбъектМетаданных.Автонумерация И ОбъектМетаданных.ДлинаКода > 0 Тогда 
				ДанныеЯчейки = ПланыВидовХарактеристик[ОписаниеОбъекта.НазваниеОбъекта].НайтиПоКоду(ЗначениеЯчейки);
			КонецЕсли;
			Если Не ЗначениеЗаполнено(ДанныеЯчейки) Тогда 
				ДанныеЯчейки = ПланыВидовХарактеристик[ОписаниеОбъекта.НазваниеОбъекта].НайтиПоНаименованию(ЗначениеЯчейки, Истина);
			КонецЕсли;
		Иначе
			ДанныеЯчейки =  Строка(ЗначениеЯчейки);
		КонецЕсли;
		Если ЗначениеЗаполнено(ДанныеЯчейки) Тогда 
			Прервать;
		КонецЕсли;
	КонецЦикла;
	
	Возврат ДанныеЯчейки;
	
КонецФункции

Функция НайтиПоНаименованию(ЗначениеЯчейки, ОбъектМетаданных, Колонка)
	
	Запрос = Новый Запрос;
	
	Если ОбъектМетаданных.Иерархический
	   И ОбъектМетаданных.ВидИерархии = Метаданные.СвойстваОбъектов.ВидИерархии.ИерархияГруппИЭлементов Тогда
	
		Запрос.Текст =
		"ВЫБРАТЬ ПЕРВЫЕ 1
		|	ИмяСправочника.Ссылка КАК Ссылка
		|ИЗ
		|	#ИмяСправочника КАК ИмяСправочника
		|ГДЕ
		|	ИмяСправочника.Наименование = &Наименование
		|	И ИмяСправочника.ЭтоГруппа = &ЭтоГруппа
		|
		|УПОРЯДОЧИТЬ ПО
		|	ИмяСправочника.ЭтоГруппа";
		
		Если Колонка.Использование = "ДляГруппы" Тогда
			Запрос.УстановитьПараметр("ЭтоГруппа", Истина);
		ИначеЕсли Колонка.Использование = "ДляЭлемента" Тогда
			Запрос.УстановитьПараметр("ЭтоГруппа", Ложь);
		Иначе
			Запрос.Текст = СтрЗаменить(Запрос.Текст, "И ИмяСправочника.ЭтоГруппа = &ЭтоГруппа", "");
		КонецЕсли;
		
	Иначе
		
		Запрос.Текст =
		"ВЫБРАТЬ ПЕРВЫЕ 1
		|	ИмяСправочника.Ссылка КАК Ссылка
		|ИЗ
		|	#ИмяСправочника КАК ИмяСправочника
		|ГДЕ
		|	ИмяСправочника.Наименование = &Наименование";
		
	КонецЕсли;
	
	Запрос.Текст = СтрЗаменить(Запрос.Текст, "#ИмяСправочника", ОбъектМетаданных.ПолноеИмя());
	Запрос.УстановитьПараметр("Наименование", ЗначениеЯчейки);
	
	РезультатЗапроса = Запрос.Выполнить();
	
	Если РезультатЗапроса.Пустой() Тогда
		Возврат Неопределено;
	КонецЕсли;
	
	Выборка = РезультатЗапроса.Выбрать();
	
	Если Выборка.Следующий() Тогда
		Возврат Выборка.Ссылка;
	КонецЕсли;
	
	Возврат Неопределено;
	
КонецФункции


Процедура ОпределитьПозицииКолонокВМакете(ШаблонСДанными, ИнформацияПоКолонкам)
	
	ОбластьЗаголовка = ОбластьЗаголовкаШаблонаТаблицы(ШаблонСДанными);
	
	СоответствиеКолонок = Новый Соответствие;
	Для НомерКолонки = 1 По ОбластьЗаголовка.ШиринаТаблицы Цикл 
		Ячейка=ШаблонСДанными.ПолучитьОбласть(1, НомерКолонки, 1, НомерКолонки).ТекущаяОбласть;
		ИмяКолонкиВМакете = Ячейка.Текст;
		СоответствиеКолонок.Вставить(ИмяКолонкиВМакете, НомерКолонки);
	КонецЦикла;
	
	Для каждого Колонка Из ИнформацияПоКолонкам Цикл 
		Позиция = СоответствиеКолонок.Получить(Колонка.ПредставлениеКолонки);
		Если Позиция <> Неопределено Тогда 
			Колонка.Позиция = Позиция;
		Иначе
			Колонка.Позиция = -1;
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

#Область ПодготовкаКЗагрузкеДанных

Функция ОбластьЗаголовкаШаблонаТаблицы(Шаблон)
	
	ВысотаШапки = 1;
	Для НомерКолонки = 1 По Шаблон.ШиринаТаблицы Цикл
		Ячейка = Шаблон.ПолучитьОбласть(2, НомерКолонки, 2, НомерКолонки).ТекущаяОбласть;
		Если ЗначениеЗаполнено(Ячейка.Текст) Тогда
			ВысотаШапки = 2;
			Прервать;
		КонецЕсли;
	КонецЦикла;
	ОбластьЗаголовокТаблицы = Шаблон.ПолучитьОбласть(1, 1, ВысотаШапки, Шаблон.ШиринаТаблицы);
	
	Возврат ОбластьЗаголовокТаблицы;
	
КонецФункции

// Формирует макет табличного документа на основание реквизитов справочника для универсальной загрузки.
//
Процедура ИнформациюПоКолонкамИзРеквизитовСправочника(ПараметрыЗагрузки, ИнформацияПоКолонкам)
	
	ИнформацияПоКолонкам.Очистить();
	Позиция = 1;
	
	МетаданныеСправочника= ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ПараметрыЗагрузки.ПолноеИмяОбъекта); // ОбъектМетаданныхСправочник, ОбъектМетаданныхДокумент
	
	Если НЕ МетаданныеСправочника.Автонумерация И МетаданныеСправочника.ДлинаКода > 0  Тогда
		СоздатьКолонкуСтандартныеРеквизиты(ИнформацияПоКолонкам, МетаданныеСправочника, "Код", Позиция);
		Позиция = Позиция + 1;
	КонецЕсли;
	
	Если МетаданныеСправочника.ДлинаНаименования > 0  Тогда
		СоздатьКолонкуСтандартныеРеквизиты(ИнформацияПоКолонкам, МетаданныеСправочника, "Наименование", Позиция);
		Позиция = Позиция + 1;
	КонецЕсли;
	
	Если МетаданныеСправочника.Иерархический Тогда
		СоздатьКолонкуСтандартныеРеквизиты(ИнформацияПоКолонкам, МетаданныеСправочника, "Родитель", Позиция);
		Позиция = Позиция + 1;
	КонецЕсли;
	 
	Если МетаданныеСправочника.Владельцы.Количество() > 0 Тогда
		СоздатьКолонкуСтандартныеРеквизиты(ИнформацияПоКолонкам, МетаданныеСправочника, "Владелец", Позиция);
		Позиция = Позиция + 1;
	КонецЕсли;
	
	Для каждого Реквизит Из МетаданныеСправочника.Реквизиты Цикл
		
		Если Реквизит.Имя = "Идентификатор" Тогда
			Продолжить;
		КонецЕсли;
		
		Если Реквизит.Тип.СодержитТип(Тип("ХранилищеЗначения")) Тогда
			Продолжить;
		КонецЕсли;
		
		ОписаниеТипаКолонки = "";
		
		Если Реквизит.Тип.СодержитТип(Тип("Булево")) Тогда 
			ОписаниеТипаКолонки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Флаг, %1 или 1 / Нет или 0'"), ЗагрузкаДанныхИзФайлаКлиентСервер.ПредставлениеТекстаДаДляБулево());
		ИначеЕсли Реквизит.Тип.СодержитТип(Тип("Число")) Тогда 
			ОписаниеТипаКолонки =  СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Число, Длина: %1, Точность: %2'"),
				Строка(Реквизит.Тип.КвалификаторыЧисла.Разрядность),
				Строка(Реквизит.Тип.КвалификаторыЧисла.РазрядностьДробнойЧасти));
		ИначеЕсли Реквизит.Тип.СодержитТип(Тип("Строка")) Тогда
			Если Реквизит.Тип.КвалификаторыСтроки.Длина > 0 Тогда
				ДлинаСтроки = Строка(Реквизит.Тип.КвалификаторыСтроки.Длина);
				ОписаниеТипаКолонки =  СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Строка, макс. количество символов: %1'"), ДлинаСтроки);
			Иначе
				ОписаниеТипаКолонки = НСтр("ru = 'Строка неограниченной длины'");
			КонецЕсли;
		ИначеЕсли Реквизит.Тип.СодержитТип(Тип("Дата")) Тогда
			ОписаниеТипаКолонки = Строка(Реквизит.Тип.КвалификаторыДаты.ЧастиДаты);
		ИначеЕсли Реквизит.Тип.СодержитТип(Тип("УникальныйИдентификатор")) Тогда
			ОписаниеТипаКолонки = НСтр("ru = 'Уникальный идентификатор'");
		КонецЕсли;
		
		ШиринаКолонки = ШиринаКолонкиПоТипу(Реквизит.Тип);
		Подсказка = ?(ЗначениеЗаполнено(Реквизит.Подсказка), Реквизит.Подсказка, Реквизит.Представление()) +  Символы.ПС + ОписаниеТипаКолонки;
		ОбязательноеПоле = ?(Реквизит.ПроверкаЗаполнения = ПроверкаЗаполнения.ВыдаватьОшибку, Истина, Ложь);
		
		СтрокаИнфоПроКолонки = ИнформацияПоКолонкам.Добавить();
		СтрокаИнфоПроКолонки.ИмяКолонки = Реквизит.Имя;
		СтрокаИнфоПроКолонки.ПредставлениеКолонки = Реквизит.Представление();
		СтрокаИнфоПроКолонки.ТипКолонки = Реквизит.Тип;
		СтрокаИнфоПроКолонки.ОбязательнаДляЗаполнения = ОбязательноеПоле;
		СтрокаИнфоПроКолонки.Позиция = Позиция;
		СтрокаИнфоПроКолонки.Группа = МетаданныеСправочника.Представление();
		СтрокаИнфоПроКолонки.Видимость = Истина;
		СтрокаИнфоПроКолонки.Примечание = Подсказка;
		СтрокаИнфоПроКолонки.Ширина = ШиринаКолонки;

		Позиция = Позиция + 1;
		
	КонецЦикла;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.КонтактнаяИнформация") Тогда
		МодульУправлениеКонтактнойИнформацией = ОбщегоНазначения.ОбщийМодуль("УправлениеКонтактнойИнформацией");
		МодульУправлениеКонтактнойИнформацией.КолонкиДляЗагрузкиДанных(МетаданныеСправочника, ИнформацияПоКолонкам);
	КонецЕсли;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Свойства") Тогда
		МодульУправлениеСвойствамиСлужебный = ОбщегоНазначения.ОбщийМодуль("УправлениеСвойствамиСлужебный");
		МодульУправлениеСвойствамиСлужебный.КолонкиДляЗагрузкиДанных(МетаданныеСправочника, ИнформацияПоКолонкам);
	КонецЕсли;
	
КонецПроцедуры

// Добавление информации о колонке для стандартного реквизита при универсальной загрузке.
//
Процедура СоздатьКолонкуСтандартныеРеквизиты(ИнформацияПоКолонкам, МетаданныеСправочника, ИмяКолонки, Позиция)
	
	Реквизит = МетаданныеСправочника.СтандартныеРеквизиты[ИмяКолонки];
	Представление = МетаданныеСправочника.СтандартныеРеквизиты[ИмяКолонки].Представление();
	ТипДанных = МетаданныеСправочника.СтандартныеРеквизиты[ИмяКолонки].Тип.Типы()[0];
	ОписаниеТипа = МетаданныеСправочника.СтандартныеРеквизиты[ИмяКолонки].Тип;
	
	ШиринаКолонки = 11;
	
	Если ТипДанных = Тип("Строка") Тогда 
		ПредставлениеТипа = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Строка (не более %1 символов)'"), ОписаниеТипа.КвалификаторыСтроки.Длина);
		ШиринаКолонки = ?(ОписаниеТипа.КвалификаторыСтроки.Длина < 30, ОписаниеТипа.КвалификаторыСтроки.Длина + 1, 30);
	ИначеЕсли ТипДанных = Тип("Число") Тогда
		ПредставлениеТипа = НСтр("ru = 'Число'");
	Иначе
		Если МетаданныеСправочника.СтандартныеРеквизиты[ИмяКолонки].Тип.Типы().Количество() = 1 Тогда 
			ПредставлениеТипа = Строка(ТипДанных); 
		Иначе
			ПредставлениеТипа = "";
			Разделитель = "";
			Для каждого ТипДанные Из МетаданныеСправочника.СтандартныеРеквизиты[ИмяКолонки].Тип.Типы() Цикл 
				ПредставлениеТипа = ПредставлениеТипа  + Разделитель + Строка(ТипДанные);
				Разделитель = " или ";
			КонецЦикла;
		КонецЕсли;
	КонецЕсли;
	ТекстПримечания = Реквизит.Подсказка + Символы.ПС + ПредставлениеТипа;
	
	ОбязательнаДляЗаполнения = ?(Реквизит.ПроверкаЗаполнения = ПроверкаЗаполнения.ВыдаватьОшибку, Истина, Ложь);
	СтрокаИнфоПроКолонки = ИнформацияПоКолонкам.Добавить();
	СтрокаИнфоПроКолонки.ИмяКолонки = ИмяКолонки;
	СтрокаИнфоПроКолонки.ПредставлениеКолонки = Представление;
	СтрокаИнфоПроКолонки.ТипКолонки = ОписаниеТипа;
	СтрокаИнфоПроКолонки.ОбязательнаДляЗаполнения = ОбязательнаДляЗаполнения;
	СтрокаИнфоПроКолонки.Позиция = Позиция;
	СтрокаИнфоПроКолонки.Группа = МетаданныеСправочника.Представление();
	СтрокаИнфоПроКолонки.Видимость = Истина;
	СтрокаИнфоПроКолонки.Примечание = ТекстПримечания;
	СтрокаИнфоПроКолонки.Ширина = ШиринаКолонки;
	
КонецПроцедуры

// Определяет состав колонок для загрузки данных.
//
// Параметры:
//  ПараметрыЗагрузки - Структура
//  ИнформацияПоКолонкам - ТаблицаЗначений:
//   * ИмяКолонки - Строка
//   * ПредставлениеКолонки - Строка
//   * ТипКолонки - ОписаниеТипов
//   * ОбязательнаДляЗаполнения - Булево
//   * Использование - Строка
//   * Позиция - Число
//   * Группа - Строка
//   * Видимость - Булево
//   * Примечание - Строка
//   * Ширина - Число
//  ИменаДобавляемыхКолонок - Неопределено
//
Процедура ОпределитьИнформацияПоКолонкам(ПараметрыЗагрузки, ИнформацияПоКолонкам, ИменаДобавляемыхКолонок = Неопределено) Экспорт
	
	Если ПараметрыЗагрузки.ТипЗагрузки = "ПрикладнаяЗагрузка" Тогда
		
		Если ПараметрыЗагрузки.Свойство("Макет") Тогда
			Макет = ПараметрыЗагрузки.Макет;
		Иначе
			Макет = МенеджерОбъекта(ПараметрыЗагрузки.ПолноеИмяОбъекта).ПолучитьМакет("ЗагрузкаИзФайла");
		КонецЕсли;
		
		ОбластьЗаголовокТаблицы = ОбластьЗаголовкаШаблонаТаблицы(Макет);
		
		Если ИнформацияПоКолонкам.Количество() = 0 Тогда
			СоздатьИнформациюПоКолонкамНаОснованиеШаблона(ОбластьЗаголовокТаблицы, ПараметрыЗагрузки, ИнформацияПоКолонкам, Неопределено);
		КонецЕсли;
		
	ИначеЕсли ПараметрыЗагрузки.ТипЗагрузки = "УниверсальнаяЗагрузка" Тогда
		
		ИнформацияПоКолонкамНаОснованиеРеквизитов = ИнформацияПоКолонкам.СкопироватьКолонки();
		
		Если ИнформацияПоКолонкам.Количество() = 0 Тогда
			ИнформациюПоКолонкамИзРеквизитовСправочника(ПараметрыЗагрузки, ИнформацияПоКолонкам);
		Иначе
			ИнформациюПоКолонкамИзРеквизитовСправочника(ПараметрыЗагрузки, ИнформацияПоКолонкамНаОснованиеРеквизитов);
		КонецЕсли;
		
	ИначеЕсли ПараметрыЗагрузки.ТипЗагрузки = "ВнешняяЗагрузка" Тогда
		
		ОбластьЗаголовокТаблицы = ОбластьЗаголовкаШаблонаТаблицы(ПараметрыЗагрузки.Макет);
		ОбластьЗаголовокТаблицы.Защита = Истина;
		
		Если ИнформацияПоКолонкам.Количество() = 0 Тогда
			СоздатьИнформациюПоКолонкамНаОснованиеШаблона(ОбластьЗаголовокТаблицы, ПараметрыЗагрузки, ИнформацияПоКолонкам);
		КонецЕсли;
		
	ИначеЕсли ПараметрыЗагрузки.ТипЗагрузки = "ТабличнаяЧасть" Тогда
		
		Если ИнформацияПоКолонкам.Количество() = 0 Тогда
			ОпределитьИнформацияПоКолонкамТабличнаяЧасть(ИнформацияПоКолонкам, Макет, ОбластьЗаголовокТаблицы, ПараметрыЗагрузки);
		Иначе
			ОбъектМетаданных = Метаданные.НайтиПоПолномуИмени(ПараметрыЗагрузки.ПолноеИмяОбъекта);
			
			Если ОбъектМетаданных = Неопределено Тогда
				ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Загрузка данных из файла в табличную часть не поддерживается для объекта с типом: %1'"),
					ПараметрыЗагрузки.ПолноеИмяОбъекта);
				ВызватьИсключение ТекстОшибки;
			КонецЕсли;
			
			Если ОбъектМетаданных.Родитель().Макеты.Найти(ПараметрыЗагрузки.Макет) = Неопределено Тогда
				ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
					НСтр("ru = 'Загрузка данных из файла в табличную часть не поддерживается, т.к. отсутствует макет %1 у объекта с типом: %2'"),
					ПараметрыЗагрузки.Макет, ПараметрыЗагрузки.ПолноеИмяОбъекта);
				ВызватьИсключение ТекстОшибки;
			КонецЕсли;
			
			Макет = МенеджерОбъекта(ПараметрыЗагрузки.ПолноеИмяОбъекта).ПолучитьМакет(ПараметрыЗагрузки.Макет);
			ОбластьЗаголовокТаблицы = ОбластьЗаголовкаШаблонаТаблицы(Макет);
		КонецЕсли;
		
	КонецЕсли;
	
	ТребуетсяПересчетПозиций = Ложь;
	СписокКолонокСФункциональнымиОпциями = КолонкиЗависимыеОтФункциональныхОпций(ПараметрыЗагрузки.ПолноеИмяОбъекта);
	Для каждого ФункциональнаяОпцияКолонкиВключена Из СписокКолонокСФункциональнымиОпциями Цикл 
		СтрокаСИнформациейОКолонке = ИнформацияПоКолонкам.Найти(ФункциональнаяОпцияКолонкиВключена.Ключ, "ИмяКолонки");
		Если СтрокаСИнформациейОКолонке <> Неопределено Тогда
			Если НЕ ФункциональнаяОпцияКолонкиВключена.Значение Тогда
				ИнформацияПоКолонкам.Удалить(СтрокаСИнформациейОКолонке);
				ТребуетсяПересчетПозиций = Истина;
			КонецЕсли;
		Иначе
			Если ФункциональнаяОпцияКолонкиВключена.Значение Тогда
				Если ПараметрыЗагрузки.ТипЗагрузки = "УниверсальнаяЗагрузка" Тогда
					СтрокаСКолонкой = ИнформацияПоКолонкамНаОснованиеРеквизитов.Найти(ФункциональнаяОпцияКолонкиВключена.Ключ, "ИмяКолонки");
					НоваяСтрока = ИнформацияПоКолонкам.Добавить();
					ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаСКолонкой);
				Иначе
					СоздатьИнформациюПоКолонкамНаОснованиеШаблона(ОбластьЗаголовокТаблицы, ПараметрыЗагрузки, ИнформацияПоКолонкам, ФункциональнаяОпцияКолонкиВключена.Ключ);
				КонецЕсли;
				ТребуетсяПересчетПозиций = Истина;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
	Если ТребуетсяПересчетПозиций Тогда
		ИнформацияПоКолонкам.Сортировать("Позиция");
		Позиция = 1;
		Для каждого Колонка Из ИнформацияПоКолонкам Цикл
			Колонка.Позиция = Позиция;
			Позиция = Позиция + 1;
		КонецЦикла;
	КонецЕсли;
	
КонецПроцедуры

Процедура ОпределитьИнформацияПоКолонкамТабличнаяЧасть(Знач ИнформацияПоКолонкам, Макет, ОбластьЗаголовокТаблицы, Знач ПараметрыЗагрузки)
	
	СтруктураНаименованияОбъекта = РазложитьПолноеИмяОбъекта(ПараметрыЗагрузки.ПолноеИмяОбъекта);
	ИмяОбъектаМетаданных = СтруктураНаименованияОбъекта.ТипОбъекта + "." + СтруктураНаименованияОбъекта.НазваниеОбъекта;
	
	ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ИмяОбъектаМетаданных);
	Если ОбъектМетаданных = Неопределено Тогда
		ТекстОшибки = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Загрузка данных из файла в табличную часть не поддерживается для объектов типа: %1'"),
				ИмяОбъектаМетаданных);
		ВызватьИсключение ТекстОшибки;
	КонецЕсли;
	
	МакетыОбъектаМетаданных = ОбъектМетаданных.Макеты;
	
	ПараметрыЗагрузкиИзФайла = ПараметрыЗагрузкиИзФайлаВТЧ(ПараметрыЗагрузки.ПолноеИмяОбъекта, ПараметрыЗагрузки.ДополнительныеПараметры);
	ПараметрыЗагрузкиИзФайла.Вставить("ПолноеИмяОбъекта", ПараметрыЗагрузки.ПолноеИмяОбъекта);
	
	МенеджерОбъекта = ОбщегоНазначения.МенеджерОбъектаПоПолномуИмени(ПараметрыЗагрузки.ПолноеИмяОбъекта);
	МенеджерОбъекта.УстановитьПараметрыЗагрузкиИзФайлаВТЧ(ПараметрыЗагрузкиИзФайла);
	
	МакетМетаданные = МакетыОбъектаМетаданных.Найти(ПараметрыЗагрузки.Макет); // ОбъектМетаданныхМакет
	Если МакетМетаданные = Неопределено Тогда
		МакетМетаданные= МакетыОбъектаМетаданных.Найти("ЗагрузкаИзФайла" + СтруктураНаименованияОбъекта.ИмяТабличнойЧасти);
		Если МакетМетаданные = Неопределено Тогда
			МакетМетаданные = МакетыОбъектаМетаданных.Найти("ЗагрузкаИзФайла");
		КонецЕсли;
	КонецЕсли;
	
	Если МакетМетаданные <> Неопределено Тогда
		Макет = МенеджерОбъекта.ПолучитьМакет(МакетМетаданные.Имя);
	Иначе
		ВызватьИсключение НСтр("ru = 'Не найден макет для загрузки данных из файла'");
	КонецЕсли;
	
	ЗаголовокТаблицы = ОбластьЗаголовкаШаблонаТаблицы(Макет);
	Если ИнформацияПоКолонкам.Количество() = 0 Тогда
		СоздатьИнформациюПоКолонкамНаОснованиеШаблона(ЗаголовокТаблицы, ПараметрыЗагрузкиИзФайла, ИнформацияПоКолонкам);
	КонецЕсли;
	
	ОбластьЗаголовокТаблицы = ОбластьЗаголовкаШаблонаТаблицы(Макет);

КонецПроцедуры

// Заполняет таблицу о колонках в макете. Информация используется для построения таблицы сопоставления.
//
// Параметры:
//  ОбластьЗаголовокТаблицы  - ТабличныйДокумент - область заголовка макета.
//  ПараметрыЗагрузкиИзФайла - Структура - параметры загрузки.
//  ИнформацияПоКолонкам     - ТаблицаЗначений - ОписаниеТабличнойЧасти с описание колонок.
//  ИменаДобавляемыхКолонок  - Строка - список добавляемых колонок через запятую. Если значение не заполонено, то
//                                      добавляются все.
//
Процедура СоздатьИнформациюПоКолонкамНаОснованиеШаблона(ОбластьЗаголовокТаблицы, ПараметрыЗагрузкиИзФайла, ИнформацияПоКолонкам, ИменаДобавляемыхКолонок = Неопределено)
	
	ВыборочноеДобавление = Ложь;
	Если ЗначениеЗаполнено(ИменаДобавляемыхКолонок) Тогда
		ВыборочноеДобавление = Истина;
		МассивДобавляемыхКолонок = СтрРазделить(ИменаДобавляемыхКолонок, ",", Ложь);
		Позиция = ИнформацияПоКолонкам.Количество() + 1;
	Иначе
		ИнформацияПоКолонкам.Очистить();
		Позиция = 1;
	КонецЕсли;
	
	Если ПараметрыЗагрузкиИзФайла.Свойство("ТипДанныхКолонки") Тогда
		СоответствиеТипаДанныхКолонок = ПараметрыЗагрузкиИзФайла.ТипДанныхКолонки;
	Иначе
		СоответствиеТипаДанныхКолонок = Новый Соответствие;
	КонецЕсли;
	
	ВысотаШапки = ОбластьЗаголовокТаблицы.ВысотаТаблицы;
	Если ВысотаШапки = 2 Тогда
		НомерКолонки = 1;
		Группы = Новый Соответствие;
		ИспользуетсяГруппировка = Истина;
		Пока НомерКолонки <= ОбластьЗаголовокТаблицы.ШиринаТаблицы Цикл
			Область = ОбластьЗаголовокТаблицы.ПолучитьОбласть(1, НомерКолонки);
			Ячейка = ОбластьЗаголовокТаблицы.ПолучитьОбласть(1, НомерКолонки, 1, НомерКолонки).ТекущаяОбласть;
			Группа = Ячейка.Текст;
			Для Индекс = НомерКолонки По НомерКолонки + Область.ШиринаТаблицы -1 Цикл
				Группы.Вставить(Индекс, Группа);
			КонецЦикла;
			НомерКолонки = НомерКолонки + Область.ШиринаТаблицы;
		КонецЦикла;
	Иначе
		ИспользуетсяГруппировка = Ложь;
	КонецЕсли;
	
	ПредопределенныеОбластиМакета = ПредопределенныеОбластиМакета();
	ОбъектМетаданных = ОбщегоНазначения.ОбъектМетаданныхПоПолномуИмени(ПараметрыЗагрузкиИзФайла.ПолноеИмяОбъекта);
	
	Для НомерКолонки = 1 По ОбластьЗаголовокТаблицы.ШиринаТаблицы Цикл
		Ячейка = ОбластьЗаголовокТаблицы.ПолучитьОбласть(ВысотаШапки, НомерКолонки, ВысотаШапки, НомерКолонки).ТекущаяОбласть;
		
		Если Ячейка.Имя = "R1C1" Тогда
			ИмяРеквизита = ?(ЗначениеЗаполнено(Ячейка.ПараметрРасшифровки), Ячейка.ПараметрРасшифровки, Ячейка.Текст);
			ПредставлениеРеквизита = ?(ЗначениеЗаполнено(Ячейка.Текст), Ячейка.Текст, Ячейка.ПараметрРасшифровки);
			Родитель = ?(ЗначениеЗаполнено(Ячейка.ПараметрРасшифровки), Ячейка.ПараметрРасшифровки, Ячейка.Текст);
		Иначе
			ИмяРеквизита = Ячейка.Имя;
			ПредставлениеРеквизита = ?(ЗначениеЗаполнено(Ячейка.Текст), Ячейка.Текст, Ячейка.Имя);
			Родитель = ?(ЗначениеЗаполнено(Ячейка.ПараметрРасшифровки), Ячейка.ПараметрРасшифровки, Ячейка.Имя);
		КонецЕсли;
		
		Если СтрСравнить(ПредставлениеРеквизита, ПредопределенныеОбластиМакета.ДополнительныеРеквизиты) = 0 Тогда
			Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Свойства") Тогда
				МодульУправлениеСвойствамиСлужебный = ОбщегоНазначения.ОбщийМодуль("УправлениеСвойствамиСлужебный");
				МодульУправлениеСвойствамиСлужебный.КолонкиДляЗагрузкиДанных(ОбъектМетаданных, ИнформацияПоКолонкам);
			КонецЕсли;
		ИначеЕсли СтрСравнить(ПредставлениеРеквизита, ПредопределенныеОбластиМакета.КонтактнаяИнформация) = 0 Тогда
			
			Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.КонтактнаяИнформация") Тогда
				МодульУправлениеКонтактнойИнформацией = ОбщегоНазначения.ОбщийМодуль("УправлениеКонтактнойИнформацией");
				МодульУправлениеКонтактнойИнформацией.КолонкиДляЗагрузкиДанных(ОбъектМетаданных, ИнформацияПоКолонкам);
			КонецЕсли;
		Иначе
			ТипДанныхКолонки = Новый ОписаниеТипов("Строка");
			Если СоответствиеТипаДанныхКолонок <> Неопределено Тогда
				ТипДанныхКолонкиПереопределенный = СоответствиеТипаДанныхКолонок.Получить(ИмяРеквизита);
				Если ТипДанныхКолонкиПереопределенный <> Неопределено Тогда
					ТипДанныхКолонки = ТипДанныхКолонкиПереопределенный;
				КонецЕсли;
			КонецЕсли;
			
			Если ВыборочноеДобавление И МассивДобавляемыхКолонок.Найти(ИмяРеквизита) = Неопределено Тогда
				Продолжить;
			КонецЕсли;
			
			Если ЗначениеЗаполнено(ИмяРеквизита) Тогда
				
				ОбязательнаДляЗаполнения = Ячейка.Шрифт.Полужирный = Истина
				                           Или ПараметрыЗагрузкиИзФайла.ОбязательныеКолонки.Найти(ИмяРеквизита) <> Неопределено;
				
				ПримечаниеВШапкеКолонки = Ячейка.Примечание.Текст + ?(ОбязательнаДляЗаполнения,
					Символы.ПС + НСтр("ru='Обязательно для заполнения.'"), "");
				
				СтрокаИнфоПроКолонки                          = ИнформацияПоКолонкам.Добавить();
				СтрокаИнфоПроКолонки.ИмяКолонки               = ИмяРеквизита;
				СтрокаИнфоПроКолонки.ПредставлениеКолонки     = ПредставлениеРеквизита;
				СтрокаИнфоПроКолонки.ТипКолонки               = ТипДанныхКолонки;
				СтрокаИнфоПроКолонки.ОбязательнаДляЗаполнения = ОбязательнаДляЗаполнения;
				СтрокаИнфоПроКолонки.Позиция                  = Позиция;
				СтрокаИнфоПроКолонки.Родитель                 = Родитель;
				СтрокаИнфоПроКолонки.Видимость                = Истина;
				СтрокаИнфоПроКолонки.Примечание               = ПримечаниеВШапкеКолонки;
				СтрокаИнфоПроКолонки.Ширина                   = Ячейка.ШиринаКолонки;
				
				Если ОбъектМетаданных <> Неопределено И ОбщегоНазначения.ЭтоСправочник(ОбъектМетаданных) Тогда
					МетаданныеРеквизита = ОбъектМетаданных.Реквизиты.Найти(ИмяРеквизита);
					Если МетаданныеРеквизита <> Неопределено Тогда
						
						Если МетаданныеРеквизита.Использование = Метаданные.СвойстваОбъектов.ИспользованиеРеквизита.ДляГруппы Тогда
							СтрокаИнфоПроКолонки.Использование = "ДляГруппы";
						ИначеЕсли МетаданныеРеквизита.Использование = Метаданные.СвойстваОбъектов.ИспользованиеРеквизита.ДляГруппыИЭлемента Тогда
							СтрокаИнфоПроКолонки.Использование = "ДляГруппыИЭлемента";
						Иначе
							СтрокаИнфоПроКолонки.Использование = "ДляЭлемента";
						КонецЕсли;
						
					КонецЕсли;
				КонецЕсли;
				
				Если ИспользуетсяГруппировка Тогда
					СтрокаИнфоПроКолонки.Группа = Группы.Получить(НомерКолонки);
				КонецЕсли;
				
				Позиция = Позиция + 1;
				
			КонецЕсли;
		
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

// Возвращаемое значение:
//  Структура:
//   * ДополнительныеРеквизиты - Строка
//   * КонтактнаяИнформация - Строка
//
Функция ПредопределенныеОбластиМакета()
	
	ПредопределенныеОбластиМакета = Новый Структура();
	ПредопределенныеОбластиМакета.Вставить("ДополнительныеРеквизиты", НСтр("ru = '<Дополнительные реквизиты>'"));
	ПредопределенныеОбластиМакета.Вставить("КонтактнаяИнформация", НСтр("ru = '<Контактная информация>'"));
	
	Возврат ПредопределенныеОбластиМакета
	
КонецФункции

Функция ШиринаКолонкиПоТипу(Тип) 
	
	ШиринаКолонки = 20;
	Если Тип.СодержитТип(Тип("Булево")) Тогда 
		ШиринаКолонки = 3;
	ИначеЕсли Тип.СодержитТип(Тип("Число")) Тогда 
		ШиринаКолонки = Тип.КвалификаторыЧисла.Разрядность + 1;
	ИначеЕсли Тип.СодержитТип(Тип("Строка")) Тогда 
		Если Тип.КвалификаторыСтроки.Длина > 0 Тогда 
			ШиринаКолонки = ?(Тип.КвалификаторыСтроки.Длина > 20, 20, Тип.КвалификаторыСтроки.Длина);
		Иначе
			ШиринаКолонки = 20;
		КонецЕсли;
	ИначеЕсли Тип.СодержитТип(Тип("Дата")) Тогда 
		ШиринаКолонки = 12;
	ИначеЕсли Тип.СодержитТип(Тип("УникальныйИдентификатор")) Тогда 
		ШиринаКолонки = 20;
	Иначе
		Для каждого ТипОбъекта Из  Тип.Типы() Цикл
			МетаданныеОбъекта = Метаданные.НайтиПоТипу(ТипОбъекта); // ОбъектМетаданныхСправочник
			СтруктураОбъекта = РазложитьПолноеИмяОбъекта(МетаданныеОбъекта.ПолноеИмя());
			Если СтруктураОбъекта.ТипОбъекта = "Справочник" Тогда 
				Если НЕ МетаданныеОбъекта.Автонумерация И МетаданныеОбъекта.ДлинаКода > 0  Тогда
					ШиринаКолонки = МетаданныеОбъекта.ДлинаКода + 1;
				КонецЕсли;
				Если МетаданныеОбъекта.ДлинаНаименования > 0  Тогда
					Если МетаданныеОбъекта.ДлинаНаименования > ШиринаКолонки Тогда
						ШиринаКолонки = ?(МетаданныеОбъекта.ДлинаНаименования > 30, 30, МетаданныеОбъекта.ДлинаНаименования + 1);
					КонецЕсли;
			КонецЕсли;
		ИначеЕсли СтруктураОбъекта.ТипОбъекта = "Перечисление" Тогда
				ДлинаПредставления =  СтрДлина(МетаданныеОбъекта.Представление());
				ШиринаКолонки = ?( ДлинаПредставления > 30, 30, ДлинаПредставления + 1);
			КонецЕсли;
		КонецЦикла;
	КонецЕсли;
	
	Возврат ШиринаКолонки;
	
КонецФункции

// Параметры:
//  Ячейка - ТабличныйДокумент
//  Текст - Строка
//  Ширина - Число
//  Подсказка - Строка
//  ОбязательноеПоле - Булево
//  Имя - Строка
//
Процедура ЗаполнитьЯчейкуЗаголовкаМакета(Ячейка, Текст, Ширина, Подсказка, ОбязательноеПоле, Имя = "")
	
	Ячейка.ТекущаяОбласть.Текст = Текст;
	Ячейка.ТекущаяОбласть.Имя = Имя;
	Ячейка.ТекущаяОбласть.ПараметрРасшифровки = Имя;
	Ячейка.ТекущаяОбласть.ЦветФона =  ЦветаСтиля.ЦветФонаШапкиОтчета;
	Ячейка.ТекущаяОбласть.ШиринаКолонки = Ширина;
	Ячейка.ТекущаяОбласть.Примечание.Текст = Подсказка;
	Если ОбязательноеПоле Тогда 
		Ячейка.ТекущаяОбласть.Шрифт = ШрифтыСтиля.ВажнаяНадписьШрифт;
	Иначе
		Ячейка.ТекущаяОбласть.Шрифт = Неопределено;
	КонецЕсли;
	
КонецПроцедуры

// Создает шапку бланка по информации о колонках.
//
Функция ШапкаБланкаДляЗаполненияПоИнформацииПоКолонкам(ИнформацияПоКолонкам) Экспорт

	ТабличныйДокумент = Новый ТабличныйДокумент;
	КолонкиИмеютГруппировку = ЗагрузкаДанныхИзФайлаКлиентСервер.КолонкиИмеютГруппировку(ИнформацияПоКолонкам);
	Если КолонкиИмеютГруппировку Тогда
		ОбластьЗаголовок = ПолучитьМакет("ПростойШаблон").ПолучитьОбласть("Шапка2Строки");
		Линия = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная);
		НомерСтроки = 2;
	Иначе
		ОбластьЗаголовок = ПолучитьМакет("ПростойШаблон").ПолучитьОбласть("Заголовок");
		НомерСтроки = 1;
	КонецЕсли;
	ИнформацияПоКолонкам.Сортировать("Позиция");
	
	Группа = Неопределено;
	ПозицияНачалоГруппы = 1;
	Сдвиг = 0;
	Для Позиция = 0 По ИнформацияПоКолонкам.Количество() -1 Цикл
		Колонка = ИнформацияПоКолонкам.Получить(Позиция);
		
		Если Колонка.Видимость = Истина Тогда
			Если Группа = Неопределено Тогда
				Группа = Колонка.Группа;
			КонецЕсли;
			ОбластьИмяКолонки = ОбластьЗаголовок.Область(НомерСтроки, 1, НомерСтроки, 1);
			ОбластьИмяКолонки.Имя = Колонка.ИмяКолонки;
			ОбластьИмяКолонки.Расшифровка = Колонка.Группа;
			ОбластьИмяКолонки.Примечание.Текст = Колонка.Примечание;
			Если Колонка.ОбязательнаДляЗаполнения Тогда
				ОбластьИмяКолонки.Шрифт = ШрифтыСтиля.ВажнаяНадписьШрифт;
			Иначе
				ОбластьИмяКолонки.Шрифт = Неопределено;
			КонецЕсли;
			
			ОбластьИмяКолонки.ШиринаКолонки = ?(Колонка.Ширина = 0, ШиринаКолонкиПоТипу(Колонка.ТипКолонки), Колонка.Ширина);
			ОбластьЗаголовок.Параметры.Заголовок = ?(ПустаяСтрока(Колонка.Синоним), Колонка.ПредставлениеКолонки, Колонка.Синоним);
			ТабличныйДокумент.Присоединить(ОбластьЗаголовок);
			
			Если КолонкиИмеютГруппировку Тогда
				Если Колонка.Группа <> Группа Тогда
					Область = ТабличныйДокумент.Область(1, ПозицияНачалоГруппы, 1, Позиция - Сдвиг);
					Область.Текст = Группа;
					Область.Объединить();
					Область.Обвести(Линия, Линия, Линия,Линия);
					ПозицияНачалоГруппы = Позиция + 1 - Сдвиг ;
					Группа = Колонка.Группа;
				КонецЕсли;
			КонецЕсли;
		Иначе
			Сдвиг = Сдвиг + 1;
		КонецЕсли;
	КонецЦикла;
	Если КолонкиИмеютГруппировку Тогда
		Область = ТабличныйДокумент.Область(1, ПозицияНачалоГруппы, 1, Позиция - Сдвиг);
		Область.Текст = Группа;
		Область.Объединить();
		Область.Обвести(Линия, Линия, Линия,Линия);
	КонецЕсли;
	
	Возврат ТабличныйДокумент;
КонецФункции

#КонецОбласти

// Создает таблицу значений по данным из шаблона и сохраняет ее во временное хранилище.
//
Процедура ТабличныйДокументВТаблицуЗначений(ШаблонСДанными, ИнформацияПоКолонкам, АдресЗагруженныхДанных) Экспорт
	
	ОписаниеТипаЧисло  = Новый ОписаниеТипов("Число");
	ОписаниеТипаСтрока = Новый ОписаниеТипов("Строка");
	
	ТаблицаИнформацияПоКолонкам = ИнформацияПоКолонкам.Скопировать();
	ЗагружаемыеДанные = Новый ТаблицаЗначений;
	
	Для каждого Колонка Из ТаблицаИнформацияПоКолонкам Цикл
		Если Колонка.ТипКолонки = Неопределено Тогда
			ТипКолонки = ОписаниеТипаСтрока;
		Иначе
			ТипКолонки = Колонка.ТипКолонки;
		КонецЕсли;
		ЗагружаемыеДанные.Колонки.Добавить(Колонка.ИмяКолонки, ТипКолонки, Колонка.ПредставлениеКолонки);
	КонецЦикла;
	
	ЗагружаемыеДанные.Колонки.Добавить("Идентификатор",                ОписаниеТипаЧисло,  "Идентификатор");
	ЗагружаемыеДанные.Колонки.Добавить("РезультатСопоставленияСтроки", ОписаниеТипаСтрока, "Результат");
	ЗагружаемыеДанные.Колонки.Добавить("ОписаниеОшибки",               ОписаниеТипаСтрока, "Причина");
	
	КорректировкаИдентификатора = 0;
	ВысотаШапки = ?(ЗагрузкаДанныхИзФайлаКлиентСервер.КолонкиИмеютГруппировку(ТаблицаИнформацияПоКолонкам), 2, 1);
	
	ИнициализироватьКолонки(ТаблицаИнформацияПоКолонкам, ШаблонСДанными, ВысотаШапки);
	Если Не КолонкиИнициализированы(ТаблицаИнформацияПоКолонкам) Тогда
		ИнициализироватьКолонки(ТаблицаИнформацияПоКолонкам, ШаблонСДанными, ?(ВысотаШапки = 1, 2, 1));
	КонецЕсли;
	
	Для НомерСтроки = ВысотаШапки + 1 По ШаблонСДанными.ВысотаТаблицы Цикл
		СтрокаТаблицыПустая = Истина;
		НоваяСтрока               = ЗагружаемыеДанные.Добавить();
		НоваяСтрока.Идентификатор =  НомерСтроки - КорректировкаИдентификатора - 1;
		Для НомерКолонки = 1 По ШаблонСДанными.ШиринаТаблицы Цикл
			Ячейка = ШаблонСДанными.Область(НомерСтроки, НомерКолонки, НомерСтроки, НомерКолонки);
			
			НайденнаяКолонка = НайтиИнформациюОКолонке(ТаблицаИнформацияПоКолонкам, "Позиция", НомерКолонки);
			Если НайденнаяКолонка <> Неопределено Тогда
				ИмяКолонки = НайденнаяКолонка.ИмяКолонки;
				НоваяСтрока[ИмяКолонки] = ПриведениеЗначениеКТипу(Ячейка.Текст, НайденнаяКолонка.ТипКолонки);
				Если Не ЗначениеЗаполнено(НоваяСтрока[ИмяКолонки]) И ЗначениеЗаполнено(Ячейка.Текст) Тогда
					//@skip-check query-in-loop - построчная загрузка разнородных данных.
					НоваяСтрока[ИмяКолонки] = ЗначениеЯчейки(НайденнаяКолонка, Ячейка.Текст);
				КонецЕсли;
				Если СтрокаТаблицыПустая Тогда
					СтрокаТаблицыПустая = Не ЗначениеЗаполнено(Ячейка.Текст);
				КонецЕсли;
			КонецЕсли;
		КонецЦикла;
		Если СтрокаТаблицыПустая Тогда
			ЗагружаемыеДанные.Удалить(НоваяСтрока);
			КорректировкаИдентификатора = КорректировкаИдентификатора + 1;
		КонецЕсли;
	КонецЦикла;
	
	АдресЗагруженныхДанных = ПоместитьВоВременноеХранилище(ЗагружаемыеДанные);
	
КонецПроцедуры

Функция КолонкиИнициализированы(ИнформацияПоКолонкам)
	
	Для Каждого ИнформацияПоКолонке Из ИнформацияПоКолонкам Цикл
		Если ИнформацияПоКолонке.Позиция >=0 Тогда
			Возврат Истина;
		КонецЕсли;
	КонецЦикла;
	
	Возврат Ложь;
	
КонецФункции

Функция ПриведениеЗначениеКТипу(Значение, ОписаниеТипов)
	
	Для каждого Тип Из ОписаниеТипов.Типы() Цикл
		Если Тип = Тип("Дата") Тогда
			
			Возврат СтроковыеФункцииКлиентСервер.СтрокаВДату(Значение, ОписаниеТипов.КвалификаторыДаты.ЧастиДаты);
			
		ИначеЕсли Тип = Тип("Булево") Тогда
			
			ОписаниеТипаБулево = Новый ОписаниеТипов("Булево");
			Возврат ОписаниеТипаБулево.ПривестиЗначение(Значение);
			
		ИначеЕсли Тип = Тип("Строка") Тогда
			
			ОписаниеТипаБулево = Новый ОписаниеТипов("Строка");
			Возврат ОписаниеТипаБулево.ПривестиЗначение(Значение);
			
		ИначеЕсли Тип = Тип("Число") Тогда
			
			НецифровыеСимволы = СтрСоединить(СтрРазделить(Значение, "1234567890,."));
			Значение = СтрСоединить(СтрРазделить(Значение, НецифровыеСимволы));
			ОписаниеТипаЧисло = Новый ОписаниеТипов("Число");
			Возврат ОписаниеТипаЧисло.ПривестиЗначение(Значение);
			
		КонецЕсли;
	КонецЦикла;
	
	Возврат Значение;
	
КонецФункции

Процедура ЗаполнитьТаблицуПоЗагруженнымДаннымИзФайла(ДанныеИзФайла, ШаблонСДанными, ИнформацияПоКолонкам)
	
	СтрокаЗаголовок= ДанныеИзФайла.Получить(0);
	СоответствиеКолонок = Новый Соответствие;
	
	Для каждого Колонка Из ДанныеИзФайла.Колонки Цикл
		НайденнаяКолонка = НайтиИнформациюОКолонке(ИнформацияПоКолонкам, "Синоним", СтрокаЗаголовок[Колонка.Имя]);
		Если НайденнаяКолонка = Неопределено Тогда
			НайденнаяКолонка = НайтиИнформациюОКолонке(ИнформацияПоКолонкам, "ПредставлениеКолонки", СтрокаЗаголовок[Колонка.Имя]);
		КонецЕсли;
		Если НайденнаяКолонка <> Неопределено Тогда
			СоответствиеКолонок.Вставить(НайденнаяКолонка.Позиция, Колонка.Имя);
		КонецЕсли;
	КонецЦикла;
	
	Для Индекс= 1 По ДанныеИзФайла.Количество() - 1 Цикл
		СтрокаТЗ = ДанныеИзФайла.Получить(Индекс);
		НоваяСтрока = Истина;
		Для НомерКолонки =1 По ШаблонСДанными.ШиринаТаблицы Цикл
			КолонкаВТаблице = СоответствиеКолонок.Получить(НомерКолонки);
			Колонка = ИнформацияПоКолонкам.Найти(НомерКолонки, "Позиция");
			Если Колонка <> Неопределено И Колонка.Видимость = Ложь Тогда
				Продолжить;
			КонецЕсли;
			Ячейка = ШаблонСДанными.ПолучитьОбласть(2, НомерКолонки, 2, НомерКолонки);
			Если КолонкаВТаблице <> Неопределено Тогда 
				Ячейка.ТекущаяОбласть.Текст = СтрокаТЗ[КолонкаВТаблице];
				Ячейка.ТекущаяОбласть.РазмещениеТекста = ТипРазмещенияТекстаТабличногоДокумента.Обрезать;
			Иначе
				Ячейка.ТекущаяОбласть.Текст = "";
			КонецЕсли;
			Если НоваяСтрока Тогда
				ШаблонСДанными.Вывести(Ячейка);
				НоваяСтрока = Ложь;
			Иначе
				ШаблонСДанными.Присоединить(Ячейка);
			КонецЕсли;
		КонецЦикла;
	КонецЦикла;
	
КонецПроцедуры

Функция НайтиИнформациюОКолонке(ТаблицаИнформацияПоКолонкам, ИмяКолонки, Значение)
	
	Отбор = Новый Структура(ИмяКолонки, Значение);
	НайденныеКолонки = ТаблицаИнформацияПоКолонкам.НайтиСтроки(Отбор);
	Колонка = Неопределено;
	Если НайденныеКолонки.Количество() > 0 Тогда 
		Колонка = НайденныеКолонки[0];
	КонецЕсли;
	
	Возврат Колонка;
КонецФункции

Функция ПолноеИмяОбъектаТабличнаяЧасть(ИмяОбъекта) Экспорт
	
	Результат = СтрРазделить(ИмяОбъекта, ".", Ложь);
	Если Результат.Количество() = 4 Тогда
			Объект = Метаданные.НайтиПоПолномуИмени(ИмяОбъекта);
			Если Объект <> Неопределено Тогда 
				Возврат ИмяОбъекта;
			КонецЕсли;
	ИначеЕсли Результат.Количество() = 3 Тогда
		Если Результат[2] <> "ТабличнаяЧасть" Тогда 
			ИмяОбъекта = Результат[0] + "." + Результат[1] + ".ТабличнаяЧасть." + Результат[2];
			Объект = Метаданные.НайтиПоПолномуИмени(ИмяОбъекта);
			Если Объект <> Неопределено Тогда 
				Возврат ИмяОбъекта;
			КонецЕсли;
		ИначеЕсли Результат[1] = "ТабличнаяЧасть" Тогда 
			ИмяОбъекта = "Документ." + Результат[0] + ".ТабличнаяЧасть." + Результат[2];
			Объект = Метаданные.НайтиПоПолномуИмени(ИмяОбъекта);
			Если Объект <> Неопределено Тогда 
				Возврат ИмяОбъекта;
			КонецЕсли;
			ИмяОбъекта = "Справочник." + Результат[0] + ".ТабличнаяЧасть." + Результат[2];
			Объект = Метаданные.НайтиПоПолномуИмени(ИмяОбъекта);
			Если Объект <> Неопределено Тогда 
				Возврат ИмяОбъекта;
			КонецЕсли;
			Возврат Неопределено;
		КонецЕсли;
		
		Возврат Неопределено;
	ИначеЕсли Результат.Количество() = 2 Тогда
		Если Результат[0] <> "Документ" ИЛИ Результат[0] <> "Справочник" Тогда 
			ИмяОбъекта = "Документ." + Результат[0] + ".ТабличнаяЧасть." + Результат[1];
			Объект = Метаданные.НайтиПоПолномуИмени(ИмяОбъекта);
			Если Объект <> Неопределено Тогда 
				Возврат ИмяОбъекта;
			КонецЕсли;
			ИмяОбъекта = "Справочник." + Результат[0] + ".ТабличнаяЧасть." + Результат[1];
			Объект = Метаданные.НайтиПоПолномуИмени(ИмяОбъекта);
			Если Объект <> Неопределено Тогда 
				Возврат ИмяОбъекта;
			КонецЕсли;
			Возврат Неопределено;
		КонецЕсли;
		НазваниеОбъектаМетаданных = Результат[0];
		ТипОбъектаМетаданных = Метаданные.Справочники.Найти(НазваниеОбъектаМетаданных);
		Если ТипОбъектаМетаданных <> Неопределено Тогда 
			ТипОбъектаМетаданных = "Справочник";
		Иначе
			ТипОбъектаМетаданных = Метаданные.Документы.Найти(НазваниеОбъектаМетаданных);
			Если ТипОбъектаМетаданных <> Неопределено Тогда 
				ТипОбъектаМетаданных = "Документ";
			Иначе 
				Возврат Неопределено;
			КонецЕсли;
		КонецЕсли;
	КонецЕсли;
	
	Возврат Неопределено;
	
КонецФункции

// Возвращает имя объекта в виде структуры.
//
// Параметры:
//  ПолноеИмяОбъекта - Строка
//  
// Возвращаемое значение:
//  Структура:
//    * ТипОбъекта - Строка - тип объекта.
//    * НазваниеОбъекта - Строка - название объекта.
//    * ИмяТабличнойЧасти - Строка - имя табличной части.
//
Функция РазложитьПолноеИмяОбъекта(ПолноеИмяОбъекта) Экспорт
	Результат = СтрРазделить(ПолноеИмяОбъекта, ".", Ложь);
	
	ИмяОбъекта = Новый Структура;
	ИмяОбъекта.Вставить("ПолноеИмяОбъекта", ПолноеИмяОбъекта);
	ИмяОбъекта.Вставить("ТипОбъекта");
	ИмяОбъекта.Вставить("НазваниеОбъекта");
	ИмяОбъекта.Вставить("ИмяТабличнойЧасти");
	
	Если Результат.Количество() = 2 Тогда
		Если Результат[0] = "Документ" ИЛИ Результат[0] = "Справочник" ИЛИ Результат[0] = "БизнесПроцесс" 
			ИЛИ Результат[0] = "Перечисление" ИЛИ Результат[0] = "ПланВидовХарактеристик"
			ИЛИ Результат[0] = "ПланСчетов" Тогда
				ИмяОбъекта.ТипОбъекта = Результат[0];
				ИмяОбъекта.НазваниеОбъекта = Результат[1];
		Иначе
				ИмяОбъекта.ТипОбъекта = ОпределитьТипОбъектаМетаданныхПоИмени(Результат[0]);
				ИмяОбъекта.НазваниеОбъекта = Результат[0];
				ИмяОбъекта.ИмяТабличнойЧасти = Результат[1];
		КонецЕсли;
	ИначеЕсли Результат.Количество() = 3 Тогда
		ИмяОбъекта.ТипОбъекта = Результат[0];
		ИмяОбъекта.НазваниеОбъекта = Результат[1];
		ИмяОбъекта.ИмяТабличнойЧасти = Результат[2];
	ИначеЕсли Результат.Количество() = 4 Тогда 
		ИмяОбъекта.ТипОбъекта = Результат[0];
		ИмяОбъекта.НазваниеОбъекта = Результат[1];
		ИмяОбъекта.ИмяТабличнойЧасти = Результат[3];
	ИначеЕсли Результат.Количество() = 1 Тогда
		ИмяОбъекта.ТипОбъекта = ОпределитьТипОбъектаМетаданныхПоИмени(Результат[0]);
		ИмяОбъекта.НазваниеОбъекта = Результат[0];
	КонецЕсли;

	Возврат ИмяОбъекта;
	
КонецФункции

Функция ОпределитьТипОбъектаМетаданныхПоИмени(Имя)
	
	
	Для каждого Объект Из Метаданные.Справочники Цикл 
		Если Объект.Имя = Имя Тогда 
			Возврат "Справочник";
		КонецЕсли;
	КонецЦикла;
	
	Для каждого Объект Из Метаданные.Документы Цикл 
		Если Объект.Имя = Имя Тогда 
			Возврат "Документ";
		КонецЕсли;
	КонецЦикла;
	
	Для каждого Объект Из Метаданные.Обработки Цикл 
		Если Объект.Имя = Имя Тогда 
			Возврат "Обработка";
		КонецЕсли;
	КонецЦикла;
	
	Возврат Неопределено;
КонецФункции

Функция МенеджерОбъекта(ИмяОбъектаСопоставления)
	
	МассивОбъекта = РазложитьПолноеИмяОбъекта(ИмяОбъектаСопоставления);
	Если МассивОбъекта.ТипОбъекта = "Документ" Тогда
		МенеджерОбъекта = Документы[МассивОбъекта.НазваниеОбъекта];
	ИначеЕсли МассивОбъекта.ТипОбъекта = "Справочник" Тогда
		МенеджерОбъекта = Справочники[МассивОбъекта.НазваниеОбъекта];
	ИначеЕсли МассивОбъекта.ТипОбъекта = "Обработка" Тогда
		МенеджерОбъекта = Обработки[МассивОбъекта.НазваниеОбъекта];
	Иначе
		ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Объект ""%1"" не найден'"), ИмяОбъектаСопоставления);
	КонецЕсли;
	
	Возврат МенеджерОбъекта;
	
КонецФункции

/////////////// Загрузка данных //////////////////////////

Процедура ИнициализироватьКолонки(ИнформацияПоКолонкам, ШаблонСДанными, ВысотаШапки = 1)
	
	Для каждого Строка Из ИнформацияПоКолонкам Цикл
		Строка.Позиция = -1;
	КонецЦикла;
	
	Для НомерКолонки = 1 По ШаблонСДанными.ШиринаТаблицы Цикл
		ЯчейкаЗаголовок = ШаблонСДанными.ПолучитьОбласть(ВысотаШапки, НомерКолонки, ВысотаШапки, НомерКолонки).ТекущаяОбласть;
		
		Если ЗначениеЗаполнено(ЯчейкаЗаголовок.Текст) Тогда
			Отбор = Новый Структура("Синоним", СокрЛП(ЯчейкаЗаголовок.Текст));
			НайденныеКолонка = ИнформацияПоКолонкам.НайтиСтроки(Отбор);
			Если НайденныеКолонка.Количество() > 0 Тогда
				НайденныеКолонка[0].Позиция = НомерКолонки;
			Иначе
				Отбор = Новый Структура("ПредставлениеКолонки",  СокрЛП(ЯчейкаЗаголовок.Текст));
				НайденныеКолонка = ИнформацияПоКолонкам.НайтиСтроки(Отбор);
				Если НайденныеКолонка.Количество() > 0 Тогда
					НайденныеКолонка[0].Позиция = НомерКолонки;
				КонецЕсли;
			КонецЕсли;
		КонецЕсли;
	КонецЦикла;
	
КонецПроцедуры

Процедура ЗагрузитьФайлВТаблицу(ПараметрыВызоваСервера, АдресХранилища) Экспорт
	
	Расширение = ПараметрыВызоваСервера.Расширение;
	ШаблонСДанными = ПараметрыВызоваСервера.ШаблонСДанными;
	ИмяВременногоФайла = ПараметрыВызоваСервера.ИмяВременногоФайла;
	ИнформацияПоКолонкам = ПараметрыВызоваСервера.ИнформацияПоКолонкам;
	
	Попытка
		
		Если Расширение = "csv" Тогда
			ЗагрузитьCSVФайлВТаблицу(ИмяВременногоФайла, ШаблонСДанными, ИнформацияПоКолонкам);
		Иначе
			ЗагруженныйШаблонСДанными = Новый ТабличныйДокумент;
			ЗагруженныйШаблонСДанными.Прочитать(ИмяВременногоФайла);
			
			НомерСтрокиСШапкойТаблицы = ?(ЗагрузкаДанныхИзФайлаКлиентСервер.КолонкиИмеютГруппировку(ИнформацияПоКолонкам), 2, 1);
			
			Адрес = "";
			ТабличныйДокументВТаблицуЗначений(ЗагруженныйШаблонСДанными, ИнформацияПоКолонкам, Адрес);
			ЗагруженныеДанные = ПолучитьИзВременногоХранилища(Адрес);
			
			ОбластьВывода = ШаблонСДанными.ПолучитьОбласть(НомерСтрокиСШапкойТаблицы + 1, 1, НомерСтрокиСШапкойТаблицы + 1, ЗагруженныеДанные.Колонки.Количество());
			
			Для Счетчик = 1 По ЗагруженныеДанные.Колонки.Количество() Цикл
				ОбластьЗаполнения = ОбластьВывода.Область(1, Счетчик, 1, Счетчик);
				Колонка = ИнформацияПоКолонкам.Найти(Счетчик, "Позиция");
				Если Колонка <> Неопределено И Колонка.Видимость Тогда
					ОбластьЗаполнения.Параметр = Колонка.ИмяКолонки;
					ОбластьЗаполнения.Заполнение = ТипЗаполненияОбластиТабличногоДокумента.Параметр;
				КонецЕсли;
			КонецЦикла;
			
			ВсегоСтрок = ЗагруженныеДанные.Количество();
			НомерСтроки = 1;
			Для Каждого Выборка Из ЗагруженныеДанные Цикл
				УстановитьПроцентПрогресса(ВсегоСтрок, НомерСтроки);
				ОбластьВывода.Параметры.Заполнить(Выборка);
				ШаблонСДанными.Вывести(ОбластьВывода);
				НомерСтроки = НомерСтроки + 1;
			КонецЦикла;
			
		КонецЕсли;
		
		АдресХранилища = ПоместитьВоВременноеХранилище(ШаблонСДанными, АдресХранилища);
	Исключение
		
		УдалитьВременныйФайл(ИмяВременногоФайла);
		ВызватьИсключение;
		
	КонецПопытки;
	
	УдалитьВременныйФайл(ИмяВременногоФайла);
	
КонецПроцедуры

Процедура УдалитьВременныйФайл(ИмяВременногоФайла)
	
	Файл = Новый Файл(ИмяВременногоФайла);
	Если Файл.Существует() Тогда
		
		Попытка
			УдалитьФайлы(ИмяВременногоФайла);
		Исключение
			
			ТекстПредупреждения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
				НСтр("ru = 'Не был удален временный файл ""%1"" по причине:
				|%2'"), ИмяВременногоФайла, ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
			
			ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации(), УровеньЖурналаРегистрации.Предупреждение,
				Метаданные.Обработки.ЗагрузкаДанныхИзФайла,, ТекстПредупреждения);
		
		КонецПопытки;
		
	КонецЕсли;
	
КонецПроцедуры

#Область РаботаСCSVФайлами

Процедура ЗагрузитьCSVФайлВТаблицу(ИмяФайла, ШаблонСДанными, ИнформацияПоКолонкам)
	
	Файл = Новый Файл(ИмяФайла);
	Если НЕ Файл.Существует() Тогда 
		Возврат;
	КонецЕсли;
	
	ЧтениеТекста = Новый ЧтениеТекста(ИмяФайла);
	Строка = ЧтениеТекста.ПрочитатьСтроку();
	Если Строка = Неопределено Тогда 
		ТекстСообщения = НСтр("ru = 'Не получилось загрузить данные из этого файла. Убедитесь в корректности данных в файле.'");
		ВызватьИсключение ТекстСообщения;
	КонецЕсли;
	
	КолонкиШапки = СтрРазделить(Строка, ";", Ложь);
	Источник = Новый ТаблицаЗначений;
	ПозицияКолонкиВФайле = Новый Соответствие();
	
	Позиция = 1;
	Для каждого Колонка Из КолонкиШапки Цикл
		НайденнаяКолонка = НайтиИнформациюОКолонке(ИнформацияПоКолонкам, "Синоним", Колонка);
		Если НайденнаяКолонка = Неопределено Тогда
			НайденнаяКолонка = НайтиИнформациюОКолонке(ИнформацияПоКолонкам, "ПредставлениеКолонки", Колонка);
		КонецЕсли;
		Если НайденнаяКолонка <> Неопределено Тогда
			НоваяКолонка = Источник.Колонки.Добавить();
			НоваяКолонка.Имя = НайденнаяКолонка.ИмяКолонки;
			НоваяКолонка.Заголовок = Колонка;
			ПозицияКолонкиВФайле.Вставить(Позиция, НоваяКолонка.Имя);
			Позиция = Позиция + 1;
		КонецЕсли;
	КонецЦикла;
	
	Если Источник.Колонки.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;
	
	Пока Строка <> Неопределено Цикл
		НоваяСтрока = Источник.Добавить();
		Позиция = СтрНайти(Строка, ";");
		Индекс = 0;
		Пока Позиция > 0 Цикл
			Если Источник.Колонки.Количество() < Индекс + 1 Тогда
				Прервать;
			КонецЕсли;
			ИмяКолонки = ПозицияКолонкиВФайле.Получить(Индекс + 1);
			Если ИмяКолонки <> Неопределено Тогда
				НоваяСтрока[ИмяКолонки] = Лев(Строка, Позиция - 1);
			КонецЕсли;
			Строка = Сред(Строка, Позиция + 1);
			Позиция = СтрНайти(Строка, ";");
			Индекс = Индекс + 1;
		КонецЦикла;
		Если Источник.Колонки.Количество() = Индекс + 1  Тогда
			НоваяСтрока[Индекс] = Строка;
		КонецЕсли;

		Строка = ЧтениеТекста.ПрочитатьСтроку();
	КонецЦикла;
	
	ЗаполнитьТаблицуПоЗагруженнымДаннымИзФайла(Источник, ШаблонСДанными, ИнформацияПоКолонкам);
	
КонецПроцедуры

Процедура СохранитьТаблицуВCSVФайл(ПутьКФайлу, ИнформацияПоКолонкам) Экспорт
	
	ФорматЗаголовкаДляCSV = "";
	
	Для каждого Колонка Из ИнформацияПоКолонкам Цикл 
		ФорматЗаголовкаДляCSV = ФорматЗаголовкаДляCSV + Колонка.ПредставлениеКолонки + ";";
	КонецЦикла;
	
	Если СтрДлина(ФорматЗаголовкаДляCSV) > 0 Тогда
		ФорматЗаголовкаДляCSV = Лев(ФорматЗаголовкаДляCSV, СтрДлина(ФорматЗаголовкаДляCSV)-1);
	КонецЕсли;
	
	Файл = Новый ЗаписьТекста(ПутьКФайлу);
	Файл.ЗаписатьСтроку(ФорматЗаголовкаДляCSV);
	Файл.Закрыть();
	
КонецПроцедуры

#КонецОбласти

#Область ДлительныеОперации

// Запись сопоставленных данных в программу.
//
Процедура ЗаписатьСопоставленныеДанные(ПараметрыВыгрузки, АдресХранилища) Экспорт
	
	СопоставленныеДанные = ПараметрыВыгрузки.СопоставленныеДанные;
	ИмяОбъектаСопоставления =ПараметрыВыгрузки.ИмяОбъектаСопоставления;
	ПараметрыЗагрузки = ПараметрыВыгрузки.ПараметрыЗагрузки;
	ИнформацияПоКолонкам = ПараметрыВыгрузки.ИнформацияПоКолонкам;
	
	СоздаватьЕслиНеСопоставлено = ПараметрыЗагрузки.СоздаватьЕслиНеСопоставлено;
	ОбновлятьСуществующие = ПараметрыЗагрузки.ОбновлятьСуществующие;
	
	ИмяСправочника = РазложитьПолноеИмяОбъекта(ИмяОбъектаСопоставления).НазваниеОбъекта;
	МенеджерСправочника = Справочники[ИмяСправочника]; //СправочникМенеджер
	
	ИспользуетсяУправлениеДоступом = Ложь;
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.УправлениеДоступом") Тогда
		МодульУправлениеДоступом       = ОбщегоНазначения.ОбщийМодуль("УправлениеДоступом");
		ИспользуетсяУправлениеДоступом = Истина;
	КонецЕсли;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.КонтактнаяИнформация") Тогда
		МодульУправлениеКонтактнойИнформацией = ОбщегоНазначения.ОбщийМодуль("УправлениеКонтактнойИнформацией");
		ВидыКонтактнойИнформации = МодульУправлениеКонтактнойИнформацией.ВидыКонтактнойИнформацииОбъекта(Справочники[ИмяСправочника].ПустаяСсылка());
	КонецЕсли;
	
	Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Свойства") Тогда
		Свойства = Новый Соответствие;
		МодульУправлениеСвойствами = ОбщегоНазначения.ОбщийМодуль("УправлениеСвойствами");
		ПустаяСсылкаНаОбъект = Справочники[ИмяСправочника].ПустаяСсылка();
		Если МодульУправлениеСвойствами.ИспользоватьДопРеквизиты(ПустаяСсылкаНаОбъект)
			ИЛИ МодульУправлениеСвойствами.ИспользоватьДопСведения(ПустаяСсылкаНаОбъект) Тогда
			СписокСвойств = МодульУправлениеСвойствами.СвойстваОбъекта(ПустаяСсылкаНаОбъект);
			Для каждого Свойство Из СписокСвойств Цикл
				Свойства.Вставить(Строка(Свойство), Свойство);
			КонецЦикла;
		КонецЕсли;
	КонецЕсли;
	
	ТаблицаСвойств = Новый ТаблицаЗначений;
	ТаблицаСвойств.Колонки.Добавить("Свойство");
	ТаблицаСвойств.Колонки.Добавить("Значение");
	
	НомерСтроки = 0;
	ВсегоСтрок = СопоставленныеДанные.Количество();
	Для каждого СтрокаТаблицы Из СопоставленныеДанные Цикл
		
		НеобходимоОчиститьКонтактнуюИнформацию = Ложь;
		НомерСтроки = НомерСтроки + 1;
		
		Если (ЗначениеЗаполнено(СтрокаТаблицы.ОбъектСопоставления) И НЕ ОбновлятьСуществующие) 
			ИЛИ (НЕ ЗначениеЗаполнено(СтрокаТаблицы.ОбъектСопоставления) И НЕ СоздаватьЕслиНеСопоставлено) Тогда
				СтрокаТаблицы.РезультатСопоставленияСтроки = "Пропущен";
				УстановитьПроцентПрогресса(ВсегоСтрок, НомерСтроки);
				Продолжить;
		КонецЕсли;
		
		Если ИспользуетсяУправлениеДоступом Тогда
			МодульУправлениеДоступом.ОтключитьОбновлениеКлючейДоступа(Истина);
		КонецЕсли;
		НачатьТранзакцию();
		Попытка
			Если ЗначениеЗаполнено(СтрокаТаблицы.ОбъектСопоставления) Тогда
				Блокировка = Новый БлокировкаДанных;
				ЭлементБлокировки = Блокировка.Добавить("Справочник." + ИмяСправочника);
				ЭлементБлокировки.УстановитьЗначение("Ссылка", СтрокаТаблицы.ОбъектСопоставления);
				Блокировка.Заблокировать();
				
				ЭлементСправочника = СтрокаТаблицы.ОбъектСопоставления.ПолучитьОбъект();
				СтрокаТаблицы.РезультатСопоставленияСтроки = "Обновлен";
				НеобходимоОчиститьКонтактнуюИнформацию = Истина;
				Если ЭлементСправочника = Неопределено Тогда
					ВызватьИсключение СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Номенклатура с артикулом %1 не существует.'"),
					СтрокаТаблицы.Артикул);
				КонецЕсли;
			Иначе
				ЭлементСправочника = МенеджерСправочника.СоздатьЭлемент();
				СтрокаТаблицы.ОбъектСопоставления = ЭлементСправочника;
				СтрокаТаблицы.РезультатСопоставленияСтроки = "Создан";
			КонецЕсли;
			
			Для каждого Колонка Из ИнформацияПоКолонкам Цикл 
				Если Колонка.Видимость Тогда
					Если СтрНачинаетсяС(Колонка.ИмяКолонки, "КонтактнаяИнформация_") Тогда
						ИмяВидаКИ = СтандартныеПодсистемыСервер.ПреобразоватьАдаптированноеНаименованиеКолонкиВСтроку(Сред(Колонка.ИмяКолонки, СтрДлина("КонтактнаяИнформация_") + 1));
						ВидКонтактнойИнформации = ВидыКонтактнойИнформации.Найти(ИмяВидаКИ, "Наименование");
						Если НеобходимоОчиститьКонтактнуюИнформацию Тогда
							ЭлементСправочника.КонтактнаяИнформация.Очистить();
							НеобходимоОчиститьКонтактнуюИнформацию = Ложь;
						КонецЕсли;
						Если ВидКонтактнойИнформации <> Неопределено Тогда
							Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.КонтактнаяИнформация") Тогда
								МодульУправлениеКонтактнойИнформацией = ОбщегоНазначения.ОбщийМодуль("УправлениеКонтактнойИнформацией");
								ЗначениеКонтактнойИнформации = МодульУправлениеКонтактнойИнформацией.КонтактнаяИнформацияПоПредставлению(СтрокаТаблицы[Колонка.ИмяКолонки], ВидКонтактнойИнформации.Ссылка);
								МодульУправлениеКонтактнойИнформацией.ЗаписатьКонтактнуюИнформацию(ЭлементСправочника, ЗначениеКонтактнойИнформации, ВидКонтактнойИнформации.Ссылка, ВидКонтактнойИнформации.Тип);
							КонецЕсли;
						КонецЕсли;
					ИначеЕсли СтрНачинаетсяС(Колонка.ИмяКолонки, "ДополнительныйРеквизит_") Тогда
						ДобавитьЗначениеСвойства(ТаблицаСвойств, Свойства, "ДополнительныйРеквизит_", Колонка.ИмяКолонки,  СтрокаТаблицы[Колонка.ИмяКолонки]);
					ИначеЕсли СтрНачинаетсяС(Колонка.ИмяКолонки, "Свойство_") Тогда
						ДобавитьЗначениеСвойства(ТаблицаСвойств, Свойства, "Свойство_", Колонка.ИмяКолонки,  СтрокаТаблицы[Колонка.ИмяКолонки]);
					Иначе
						ЭлементСправочника[Колонка.ИмяКолонки] = СтрокаТаблицы[Колонка.ИмяКолонки];
					КонецЕсли;
				КонецЕсли;
			КонецЦикла;
			
			УстановитьПроцентПрогресса(ВсегоСтрок, НомерСтроки);
			Если НЕ ЭлементСправочника.ПроверитьЗаполнение() Тогда
				СообщенияПользователю = ПолучитьСообщенияПользователю(Истина);
				ТекстСообщений = "";
				Разделитель = "";
				Для каждого СообщениеПользователю Из СообщенияПользователю Цикл
					Если ЗначениеЗаполнено(СообщениеПользователю.Поле) Тогда
						ТекстСообщений = ТекстСообщений + Разделитель + СообщениеПользователю.Текст;
						Разделитель = Символы.ПС;
					КонецЕсли;
				КонецЦикла;
				ВызватьИсключение ТекстСообщений;
			КонецЕсли;
			
			ЭлементСправочника.Записать();
			// Свойства записываем когда объект уже существует.
			Если ТаблицаСвойств.Количество() > 0 И ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Свойства") Тогда
				МодульУправлениеСвойствами = ОбщегоНазначения.ОбщийМодуль("УправлениеСвойствами");
				МодульУправлениеСвойствами.ЗаписатьСвойстваУОбъекта(ЭлементСправочника.Ссылка, ТаблицаСвойств);
			КонецЕсли;
			Если ИспользуетсяУправлениеДоступом Тогда
				МодульУправлениеДоступом.ОтключитьОбновлениеКлючейДоступа(Ложь);
			КонецЕсли;
			ЗафиксироватьТранзакцию();
		Исключение
			ОтменитьТранзакцию();
			Если ИспользуетсяУправлениеДоступом Тогда
				МодульУправлениеДоступом.ОтключитьОбновлениеКлючейДоступа(Ложь, Ложь);
			КонецЕсли;
			ИнформацияОбОшибке = ИнформацияОбОшибке();
			СтрокаТаблицы.РезультатСопоставленияСтроки = "Пропущен";
			СтрокаТаблицы.ОписаниеОшибки = ОбработкаОшибок.КраткоеПредставлениеОшибки(ИнформацияОбОшибке);
			
			ТекстСообщения = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
			НСтр("ru = 'Не удалось записать элемент справочника %1 по причине:
				|%2'"), 
				ИмяСправочника, ОбработкаОшибок.ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
			ЗаписьЖурналаРегистрации(СобытиеЖурналаРегистрации(), УровеньЖурналаРегистрации.Предупреждение,
				МенеджерСправочника, ЭлементСправочника.Ссылка, ТекстСообщения);
		КонецПопытки;
		
	КонецЦикла;
	
	АдресХранилища = ПоместитьВоВременноеХранилище(СопоставленныеДанные, АдресХранилища);
	
КонецПроцедуры

Процедура УстановитьПроцентПрогресса(Всего, НомерСтроки)
	Процент = НомерСтроки * 50 / Всего;
	МодульДлительныеОперации = ОбщегоНазначения.ОбщийМодуль("ДлительныеОперации");
	МодульДлительныеОперации.СообщитьПрогресс(Процент);
КонецПроцедуры

Процедура СформироватьОтчетОЗагрузкеФон(ПараметрыВыгрузки, АдресХранилища) Экспорт
	
	ТаблицаОтчет = ПараметрыВыгрузки.ТаблицаОтчет; // ТабличныйДокумент
	СопоставленныеДанные  = ПараметрыВыгрузки.СопоставленныеДанные;
	ИнформацияПоКолонкам  = ПараметрыВыгрузки.ИнформацияПоКолонкам;
	ШаблонСДанными = ПараметрыВыгрузки.ШаблонСДанными;
	ТипОтчета = ПараметрыВыгрузки.ТипОтчета;
	РассчитыватьПроцентПрогресса = ПараметрыВыгрузки.РассчитыватьПроцентПрогресса;
	
	Если Не ЗначениеЗаполнено(ТипОтчета) Тогда
		ТипОтчета = "ВсеЭлементы";
	КонецЕсли;
	
	СформироватьМакетОтчета(ТаблицаОтчет, ШаблонСДанными);
	
	КоличествоСозданных = 0;
	КоличествоОбновленных = 0;
	КоличествоПропущенных = 0;
	КоличествоПропущенныхСОшибкой = 0;
	Для НомерСтроки = 1 По СопоставленныеДанные.Количество() Цикл
		Строка = СопоставленныеДанные.Получить(НомерСтроки - 1);
		
		Ячейка = ТаблицаОтчет.ПолучитьОбласть(НомерСтроки + 1, 1, НомерСтроки + 1, 1);
		Ячейка.ТекущаяОбласть.Текст = ПредставлениеСтатусаЗагрузки(Строка.РезультатСопоставленияСтроки);
		Ячейка.ТекущаяОбласть.Расшифровка = Строка.ОбъектСопоставления;
		Ячейка.ТекущаяОбласть.Примечание.Текст = Строка.ОписаниеОшибки;
		Если Строка.РезультатСопоставленияСтроки = "Создан" Тогда 
			Ячейка.ТекущаяОбласть.ЦветТекста = ЦветаСтиля.РезультатУспехЦвет;
			КоличествоСозданных = КоличествоСозданных + 1;
		ИначеЕсли Строка.РезультатСопоставленияСтроки = "Обновлен" Тогда
			Ячейка.ТекущаяОбласть.ЦветТекста = ЦветаСтиля.ПоясняющийТекст;
			КоличествоОбновленных = КоличествоОбновленных + 1;
		Иначе
			Ячейка.ТекущаяОбласть.ЦветТекста = ЦветаСтиля.ТекстЗапрещеннойЯчейкиЦвет;
			КоличествоПропущенных = КоличествоПропущенных + 1;
			Если ЗначениеЗаполнено(Строка.ОписаниеОшибки) Тогда
				КоличествоПропущенныхСОшибкой = КоличествоПропущенныхСОшибкой + 1;
			КонецЕсли;
		КонецЕсли;
		
		Если ТипОтчета = "Новые" И Строка.РезультатСопоставленияСтроки <> "Создан" Тогда
			Продолжить;
		КонецЕсли;
		
		Если ТипОтчета = "Обновленные" И Строка.РезультатСопоставленияСтроки <> "Обновлен" Тогда 
			Продолжить;
		КонецЕсли;
		
		Если ТипОтчета = "Пропущенные" И Строка.РезультатСопоставленияСтроки <> "Пропущен" Тогда 
			Продолжить;
		КонецЕсли;
		
		ТаблицаОтчет.Вывести(Ячейка);
		Для Индекс = 1 По ИнформацияПоКолонкам.Количество() Цикл 
			Ячейка = ТаблицаОтчет.ПолучитьОбласть(НомерСтроки + 1, Индекс + 1, НомерСтроки + 1, Индекс + 1);
			
			Отбор = Новый Структура("Позиция", Индекс);
			НайденныеКолонки = ИнформацияПоКолонкам.НайтиСтроки(Отбор);
			Если НайденныеКолонки.Количество() > 0 Тогда 
				ИмяКолонки = НайденныеКолонки[0].ИмяКолонки;
				Ячейка.ТекущаяОбласть.Расшифровка = Строка.ОбъектСопоставления;
				Ячейка.ТекущаяОбласть.Текст = Строка[ИмяКолонки];
				Ячейка.ТекущаяОбласть.РазмещениеТекста = ТипРазмещенияТекстаТабличногоДокумента.Обрезать;
			КонецЕсли;
			ТаблицаОтчет.Присоединить(Ячейка);
			
		КонецЦикла;
		
		Если РассчитыватьПроцентПрогресса Тогда 
			Процент = Окр(НомерСтроки * 50 / СопоставленныеДанные.Количество()) + 50;
			МодульДлительныеОперации = ОбщегоНазначения.ОбщийМодуль("ДлительныеОперации");
			МодульДлительныеОперации.СообщитьПрогресс(Процент);
		КонецЕсли;
		
	КонецЦикла;
	
	Результат = Новый Структура;
	Результат.Вставить("ТипОтчета", ТипОтчета);
	Результат.Вставить("Всего", СопоставленныеДанные.Количество());
	Результат.Вставить("Создано", КоличествоСозданных);
	Результат.Вставить("Обновлено", КоличествоОбновленных);
	Результат.Вставить("Пропущено", КоличествоПропущенных);
	Результат.Вставить("Некорректных", КоличествоПропущенныхСОшибкой);
	Результат.Вставить("ТаблицаОтчет", ТаблицаОтчет);
	
	АдресХранилища = ПоместитьВоВременноеХранилище(Результат, АдресХранилища); 
	
КонецПроцедуры

Процедура СформироватьМакетОтчета(ТаблицаОтчет, ШаблонСДанными)
	
	ТаблицаОтчет.Очистить();
	Ячейка = ШаблонСДанными.ПолучитьОбласть(1, 1, 1, 1);
	
	ШапкаТаблицы = ШаблонСДанными.ПолучитьОбласть("R1");
	ЗаполнитьЯчейкуЗаголовкаМакета(Ячейка, НСтр("ru = 'Результат'"), 12, НСтр("ru = 'Результат загрузки данных'"), Истина);
	ТаблицаОтчет.Присоединить(ШапкаТаблицы); 
	ТаблицаОтчет.ВставитьОбласть(Ячейка.ТекущаяОбласть, ТаблицаОтчет.Область("C1"), ТипСмещенияТабличногоДокумента.ПоГоризонтали);
	
	ТаблицаОтчет.ФиксацияСверху = 1;
КонецПроцедуры

Функция ПредставлениеСтатусаЗагрузки(Статус)
	
	Если Статус = "Создан" Тогда
		Возврат НСтр("ru = 'Создан'");
	ИначеЕсли Статус = "Обновлен" Тогда
		Возврат НСтр("ru = 'Обновлен'");
	ИначеЕсли Статус = "Пропущен" Тогда
		Возврат НСтр("ru = 'Пропущен'");
	КонецЕсли;
	
	Возврат "";
	
КонецФункции

#КонецОбласти

//////////////////// Функциональные опции ///////////////////////////////////////

// Возвращает колонки-реквизиты зависимые от функциональных опций.
//
// Параметры:
//  ПолноеИмяОбъекта - Строка - полное наименование объекта.
// Возвращаемое значение:
//   -  Соответствие из КлючИЗначение:
//       * Ключ - Строка - имя колонки.
//       * Значение - Булево - признак доступности.
//
Функция КолонкиЗависимыеОтФункциональныхОпций(ПолноеИмяОбъекта)
	
	ИнформацияОФункциональныхОпциях = Новый Соответствие;
	ИмяОбъектаССуффиксомРеквизит = ПолноеИмяОбъекта + ".Реквизит.";
	
	ФункциональныеОпции = СтандартныеПодсистемыПовтИсп.ДоступностьОбъектовПоОпциям();
	Для Каждого ФункциональнаяОпция Из ФункциональныеОпции Цикл
		
		Если СтрНачинаетсяС(ФункциональнаяОпция.Ключ, ИмяОбъектаССуффиксомРеквизит) Тогда
			ИнформацияОФункциональныхОпциях.Вставить(Сред(ФункциональнаяОпция.Ключ, СтрДлина(ИмяОбъектаССуффиксомРеквизит) + 1), ФункциональнаяОпция.Значение);
		КонецЕсли;
		
	КонецЦикла;
	
	Возврат ИнформацияОФункциональныхОпциях;
	
КонецФункции

//////////////////// Служебные методы ///////////////////////////////////////////

Процедура ДобавитьЗначениеСвойства(ТаблицаСвойств, Свойства, Префикс, ИмяКолонки, Значение)
	ИмяСвойства = СокрЛП(СтандартныеПодсистемыСервер.ПреобразоватьАдаптированноеНаименованиеКолонкиВСтроку(Сред(ИмяКолонки, СтрДлина(Префикс) + 1)));
	Свойство = Свойства.Получить(ИмяСвойства); // ПланВидовХарактеристикСсылка.ДополнительныеРеквизитыИСведения
	Если Свойство <> Неопределено Тогда
		НоваяСтрокаСвойств = ТаблицаСвойств.Добавить();
		НоваяСтрокаСвойств.Свойство = Свойство.Ссылка;
		НоваяСтрокаСвойств.Значение = Значение;
	КонецЕсли;
КонецПроцедуры

// Возвращает строковую константу для формирования сообщений журнала регистрации.
//
// Возвращаемое значение:
//   Строка
//
Функция СобытиеЖурналаРегистрации() 
	
	Возврат НСтр("ru = 'Загрузка данных из файла'", ОбщегоНазначения.КодОсновногоЯзыка());
	
КонецФункции

#КонецОбласти

#КонецЕсли